Java基础
- 将一个对象作为参数传递是值传递还是引用传递?
- java中只有值传递没有引用传递!!!
- 无论是基本数据类型还是引用类型都是值传递,引用类型传递的时地址的值
- new string()和string的区别?
- new String是在堆空间中创建对象,而string是直接在常量池中赋值
- String不能被继承(String是被final修饰的,而被final修饰的类是不能被继承的)
- String s = new String("abc");创建了几个对象?
- 两个,"abc"会被放在常量池,而new出来的对象会被放在堆内存
- hashCode()与equals()之间的联系?
- 如果两个对象相等,那么它们的哈希码一定相同;但是如果两个对象有着相同的哈希码,它们不一定相等
- 一定要同时重写 equals() 和 hashCode() 吗?
- 不一定,如果对象作为键在哈希表中,那么两个方法都要重写,因为 put 和 get 的时候需要用到哈希码和 equals() 方法;如果对象不在哈希表中,仅用来判断是否相等,那么重写 equals() 就行了
- static使用注意规范:
- 静态方法只能访问静态成员,不能直接访问实例成员
- 实例方法可以访问静态成员,也可以访问实例成员
public static void main(String[] args) {
test();
}
public static void test() {
System.out.println("test");
}
public void test2() {
test();
}
public void test3() {
test2();
}
- 静态方法中不可以出现this关键字
- 代码块的使用
- 实例(构造)代码块:无static修饰,属于对象,每次构建对象都会触发一次
- 使用场景:初始化实例资源
{
System.out.println("====实例化代码块被触发====");
}
- 静态代码块:属于类,类加载时执行一次
- 使用场景:在类加载的时候做一些静态数据初始化的操作,以便后续使用
static {
System.out.println("==静态代码块被触发==");
}
- 单例模式
- 懒汉式
需要时才实例化对象,构造器以及实例需私有化,通过静态方法获取实例class SingleInstance2 { private static SingleInstance2 instance; public static SingleInstance2 getInstance() { if (instance == null) { instance = new SingleInstance2(); } return instance; } private SingleInstance2() { } }
- 饿汉式
直接实例化对象,构造器需私有化,通过类名调用class SingleInstance { public static SingleInstance instance = new SingleInstance(); private SingleInstance() { } }
- 静态方法不能够被重写
- 被final关键字标记的类不能继承,方法不能重写,变量只能赋值一次
- this和super调用构造器只能放在第一行,因此两者不能共存!!!
- 抽象类的特征
- 类有的抽象类都有
- 抽象类中可以没有抽象方法,但是有抽象方法的必须是抽象类,且继承抽象类时需实现抽象类中所有抽象方法,除非继承类也是抽象类
- 抽象类不能new,只能继承
- final与abstract互斥,加了final就不能加abstract
- JDK1.8开始后新增了哪些方法?
- 默认方法:default修饰,实现类对象调用
- 静态方法:static修饰,必须用当前接口名调用
- 私有方法:private修饰,jdk9开始才有的,只能在接口内部调用
以下为示例代码:
interface JDK8之后新增的方法 {
/**
* jdk1.8开始: 默认方法(实例方法)
* 必须用default修饰,默认用public修饰
* 只能由实现类对象调用
*/
default void run() {
go();
System.out.println("跑的挺快···");
}
/**
* 静态方法,必须使用static修饰,默认使用public修饰
* 必须接口名自己调用
*/
static void inAddr() {
System.out.println("我们都在学习Java···");
}
/**
* 私有方法,jdk1.9才开始支持,必须在接口内部才能被访问
*/
private void go() {
System.out.println("开始跑```");
}
}
class sportMan implements JDK8之后新增的方法 {
}
class test {
public static void main(String[] args) {
sportMan s = new sportMan();
s.run();
JDK8之后新增的方法.inAddr();
}
}
- 接口的注意规范
-
- 接口不能创建对象
-
- 一个类实现多个接口,多个接口中有同样的静态方法不冲突(因为静态方法只能自己类自己调)
-
- 一个类继承了父类,同时又实现了接口,父类中与接口中有同名方法,默认使用父类的
-
- 一个类实现多个接口,多个接口中存在同名的默认方法,不冲突,这个类重写该方法即可。
-
- 一个接口继承多个接口,是没有问题的,如果多个接口中存在规范冲突则不能多继承
-
多态中成员访问特点
- 方法调用:编译看左边,运行看右边
- 变量调用:编译看左边,运行看左边 (多态侧重行为多态)
-
多态的优点
(1)在多态形式下,右边对象可以实现解耦合,便于扩展和维护
(2)定义方法的时候,使用父类型作为参数,该方法就可以接收这父类的一切子类对象,体现出多态的拓展性与便利 -
匿名内部类可以作为方法的实际参数传递
-
Objects类中的equals方法更安全,可以避免空指针问题
-
JDK8新增的日期类
- LocalDate:不包含具体时间的日期
- LocalTime:不含日期的时间
- LocalDateTime:包含了日期和时间
- Instant:代表时间戳
- DateTimeFormatter:用作时间格式化和解析的
- Duration:用于计算两个 “时间” 间隔
- Period:用于计算两个 “日期” 间隔
-
正则表达式的使用
详细解析看这里->https://github.com/ziishaned/learn-regex/blob/master/translations/README-cn.md
-
Arrays的使用
public static void arrayTest() { int[] a = { 12, 2, 1, 5, 43, 32, 22}; System.out.println(Arrays.toString(a)); Arrays.sort(a); System.out.println(Arrays.toString(a)); System.out.println(Arrays.binarySearch(a, 2)); Integer[] a2 = {21, 32, 2, 4, 222, 41}; /** * 参数一:被排序的数组必须是引用类型的元素 * 参数二:匿名内部类对象,代表一个比较器对象 */ Arrays.sort(a2, new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o2 - o1; } }); System.out.println(Arrays.toString(a2)); } public static void arrayTest2() { student2[] s = new student2[2]; s[0] = new student2("韩信", 18, 66); s[1] = new student2("李白", 20, 88); Arrays.sort(s, new Comparator<student2>() { @Override public int compare(student2 o1, student2 o2) { // 浮点型可以这样 // return Double.compare(o2.score, o1.score); return o2.score - o1.score; } }); System.out.println(Arrays.toString(s)); }
-
Lambda表达式的使用
- 作用:简化匿名内部类的代码写法
- 注意事项:Lambda表达式只能简化函数式接口的匿名内部类写法
- 函数式接口表示里面只能有一个抽象方法
代码如下:
public class Lambda表达式的用法 { public static void main(String[] args) { // 标准匿名内部类 sports s = new sports() { @Override public void swim() { System.out.println("游泳中~~~"); } }; go(s); // Lambda表达式实现内部类写法 sports s2 = () -> { System.out.println("游泳中~~~");}; go(s2); // 继续简化 go(() -> { System.out.println("游泳中~~~");}); } public static void go(sports s) { System.out.println("开始~~~"); s.swim(); System.out.println("结束~~~"); } } @FunctionalInterface // 加上这个注解表示这个接口只能是函数式接口,里面只能有一个抽象方法 interface sports { void swim(); }
- Lambda表达式的省略写法
- 参数类型可以省略不写
Arrays.sort(ages1,(Integer o1,Integer o2) ->{ return o2 - o1;//降序 }); Arrays.sort(ages1,(o1, o2) ->{ return o2 - o1;//降序 });
- 如果只有一个参数,参数类型可以省略,同时()也可以省略
btn.addActionListener( (ActionEvent e)-> { system.out.println("有人点我,点我,点我!!"); }); btn.addActionListener( e -> { system.out.println("有人点我,点我,点我!!"); });
- 如果Lambda表达式的方法体代码只有一行代码。可以省略大括号不写,同时要省略分号!
btn. addActionListener( e -> system.out.println("有人点我,点我,点我!!"));
- 如果Lambda表达式的方法体代码只有一行代码。可以省略大括号不写。此时,如果这行代码是return语句,必须省略return不写,同时也必须省略";"不写
Arrays.sort(ages1,(Integer o1,Integer o2) ->{ return o2 - o1;//降序 }); Arrays.sort(ages1,(o1, o2) -> o2 - o1);
-
集合
Collection集合
List集合的遍历
- 迭代器遍历
public static void testIterator() { Collection list = new ArrayList<>(); list.add(12); list.add(13); list.add(14); list.add(15); Iterator<Integer> it = list.iterator(); while (it.hasNext()) { int value = (int) it.next(); System.out.println(value); } }
注意:在迭代器中删除元素时不要使用集合的remove,需要使用迭代器的remove
2. foreach/增强for循环public static void testForeach() { Collection<Integer> list = new ArrayList<>(); list.add(12); list.add(13); list.add(14); list.add(15); for(Integer i: list) { System.out.println(i); } }
注意:
(1) 增强for循环与for循环的区别就是增强for循环安全,循环内无法改变变量值,for循环可以
(2) 增强for循环无法遍历删除元素值
3. Lambda表达式public static void testForEach() { Collection<Integer> list = new ArrayList<>(); list.add(12); list.add(13); list.add(14); list.add(15); list.forEach(new Consumer<Integer>() { @Override public void accept(Integer t) { System.out.println(t); } }); // Lambda表达式简化 list.forEach(s -> System.out.println(s)); // 再次简化 list.forEach(System.out::println); }
注意:Lambda表达式也无法遍历删除元素值
4. for循环public static void testFor() { List<String> list = new ArrayList<>(); list.add("12"); list.add("12"); list.add("13"); list.add("14"); list.add("15"); for (int i = 0; i < list.size(); i++) { if (list.get(i).equals("12")) { list.remove("12"); } } System.out.println(list); }
注意:运行不报错,但会漏删
解决方法:倒着删,或者每次删完指针前移一位public static void testFor() { List<String> list = new ArrayList<>(); list.add("12"); list.add("12"); list.add("13"); list.add("14"); list.add("15"); for (int i = list.size()-1; i >= 0; i--) { if (list.get(i).equals("12")) { list.remove("12"); } } System.out.println(list); }
Set集合
(1)HashSet集合
特点:无序,不重复,无索引
底层架构:数组+链表+红黑树(当链表长度到8时,自动转为红黑树)也叫哈希表(2)LinkedHashSet集合
特点:有序,不重复,无索引
底层架构:哈希表,只是每个元素多了一个双链表记录存储的顺序(3)TreeSet集合
特点:不重复,无索引,可排序(按照元素大小默认升序排列)
底层架构:红黑树
注意:TreeSet集合是一定要排序的,可以将元素按照指定的规则进行排序。- 自定义数据类型使用TreeSet
- 自定义数据类型实现Comparable接口
public class Person implements Comparable<Person>{ @Override public int compareTo(Person o) { return score - o.score >= 0 ? 1 : -1; } } public static void testTreeSet() { Set<Person> sets = new TreeSet<Person>(); sets.add(new Person("韩信", 20, 66)); sets.add(new Person("韩信", 20, 66)); sets.add(new Person("李白", 18, 88)); System.out.println(sets); }
- 集合自带比较器
public static void testTreeSet() { Set<Person> sets = new TreeSet<Person>(new Comparator<Person>() { @Override public int compare(Person o1, Person o2) { // 浮点型使用Double.compare方法 // return Double.compare(o1.getScore(), o2.getScore()); return o1.getScore() - o2.getScore() >= 0 ? 1 : -1; } }); sets.add(new Person("韩信", 20, 66)); sets.add(new Person("韩信", 20, 66)); sets.add(new Person("李白", 18, 88)); System.out.println(sets); } Lambda表达式简化后: public static void testTreeSet() { Set<Person> sets = new TreeSet<Person>((o1, o2) -> o1.getScore() - o2.getScore() >= 0 ? 1 : -1); sets.add(new Person("韩信", 20, 66)); sets.add(new Person("韩信", 20, 66)); sets.add(new Person("李白", 18, 88)); System.out.println(sets); }
Map集合
Map集合遍历
- 键找值
public static void testKeySet() { Map<String, Integer> maps = new HashMap<String, Integer>(); maps.put("水果", 12); maps.put("鸡腿", 20); maps.put("鱼", 30); System.out.println(maps); Set<String> keys = maps.keySet(); for (String key: keys) { System.out.println(key + ":" + maps.get(key)); } }
- 键值对
public static void testEntrySet() { Map<String, Integer> maps = new HashMap<String, Integer>(); maps.put("水果", 12); maps.put("鸡腿", 20); maps.put("鱼", 30); System.out.println(maps); Set<Entry<String, Integer>> sets = maps.entrySet(); for (Entry<String, Integer> key: sets) { System.out.println(key.getKey() + ":" + key.getValue()); } }
- Lambda表达式
public static void testForEach() { Map<String, Integer> maps = new HashMap<String, Integer>(); maps.put("水果", 12); maps.put("鸡腿", 20); maps.put("鱼", 30); System.out.println(maps); maps.forEach(new BiConsumer<String, Integer>() { @Override public void accept(String t, Integer u) { System.out.println(t + ":" + u); } }); // 简化后 maps.forEach((t, u) -> System.out.println(t + ":" + u)); }
-
Stream流
目的:简化集合和数组操作的APIpublic static void testStream() { List<String> list = new ArrayList<String>(); Collections.addAll(list, "韩信", "李白", "孙悟空", "孙权"); list.stream().filter(t -> t.startsWith("孙") && t.length() == 3).forEach(System.out::println);; }
public static void main(String[] args) { // Collection集合获取流 Collection<String> list = new ArrayList<>(); Stream<String> stream = list.stream(); // Map集合获取流 Map<String, Integer> map = new HashMap<>(); // 键流 Stream<String> keyStream = map.keySet().stream(); // 值流 Stream<Integer> vauleStream = map.values().stream(); // 键值对流 Stream<Entry<String, Integer>> entryStream = map.entrySet().stream(); // 数组获取流 String[] s = {"韩信","李白","孙悟空","孙策"}; Stream<String> stream2 = Arrays.stream(s); Stream<String> stream3 = Stream.of(s); }
public static void testStreamMethod() { List<String> list = new ArrayList<String>(); Collections.addAll(list, "韩信", "李白", "孙悟空", "孙权"); // 跳过前面两个元素 list.stream().skip(2).forEach(System.out::println); // 获取前面两个元素 list.stream().limit(2).forEach(System.out::println); // map加工方法 list.stream().map(s -> "王者:" + s).forEach(System.out::println); // 封装成student对象 list.stream().map(s -> new student(s)).forEach(s -> System.out.println(s)); list.stream().map(student::new).forEach(System.out::println); // 合并流 Stream<String> s1 = Stream.of("韩信", "李白"); Stream<String> s2 = list.stream().skip(2); Stream<String> s3 = Stream.concat(s1, s2); s3.forEach(System.out::println); }
Stream流的收集操作
public static void testCollect() { List<String> list = new ArrayList<String>(); Collections.addAll(list, "韩信", "李白", "孙悟空", "孙权"); // 收集流 // list Stream<String> s = list.stream().skip(2); List<String> list2 = s.collect(Collectors.toList()); System.out.println(list2); // set // 注意:流只能使用一次,如需再次使用需重新创建流 Stream<String> s2 = list.stream().skip(2); Set<String> set = s2.collect(Collectors.toSet()); System.out.println(set); }
-
红黑树
红黑树调整
(1)父节点为红色,叔叔节点也是红色
调整前
调整后
(2)父节点为红,叔叔节点是黑色
调整前
调整后
-
泛型的使用
(1)通配符“?”的使用public static void testGeneric() { ArrayList<DaBen> list1 = new ArrayList<DaBen>(); list1.add(new DaBen()); list1.add(new DaBen()); list1.add(new DaBen()); ArrayList<AoDi> list2 = new ArrayList<AoDi>(); list2.add(new AoDi()); list2.add(new AoDi()); list2.add(new AoDi()); go(list1); go(list2); } public static void go(ArrayList<?> list) { } class car { } class DaBen extends car { } class AoDi extends car { }
(2)泛型的上下限
- ? extends Car:?必须是Car或者是其子类 泛型上限
- ? super Car:?必须是Car或者是其父类 泛型下限
public static void go(ArrayList<? extends car> list) { } public static void go(ArrayList<? super car> list) { }
-
异常
-
日志
-
IO流
(1)字节流,字符流如何使用?
- 字节流适合做一切文件数据的拷贝(音视频,文本)
- 字节流不适合读取中文内容输出
- 字符流适合做文本文件的操作(读,写)
(2)对象序列化
注意:序列化对象需实现Serializable接口(3)对象反序列化
(4)打印流
(5)Properties
(6)IO框架
-
多线程
(1)线程的创建方式- 继承Thread类
- 实现Runnable接口
- JDK5.0新增:实现Callable接口
由于前两种创建的线程均不能直接返回结果,故在JDK5.0提供了Callable和FutureTask来实现
public class Callable接口的使用 { public static void main(String[] args) { // 该类为Callable接口类 MyCallable myCallable = new MyCallable(100); // 该类为Runnable接口类 FutureTask<String> futureTask = new FutureTask<String>(myCallable); Thread thread = new Thread(futureTask); thread.start(); MyCallable myCallable2 = new MyCallable(200); FutureTask<String> futureTask2 = new FutureTask<String>(myCallable2); Thread thread2 = new Thread(futureTask2); thread2.start(); try { // get方法获取返回值,如果任务没有执行完成则会等待,任务完成才会提取结果 String result = futureTask.get(); String result2 = futureTask2.get(); System.out.println("第一个结果:" + result); System.out.println("第二个结果:" + result2); } catch (Exception e) { e.printStackTrace(); } } } class MyCallable implements Callable<String> { private int n; public MyCallable(int n) { super(); this.n = n; } @Override public String call() throws Exception { int sum = 0; for (int i = 0; i <= n; i++) { sum += i; } return "子线程运行的结果是:" + sum; } }
(2)线程安全出现的原因
- 存在多线程并发
- 同时访问共享资源
- 存在修改共享资源
解决方法-
同步代码块
synchronized()括号里使用共享资源作为锁对象较好 -
同步方法
-
Lock锁
-
(3)线程通信
主要是生产者与消费者这一思想
线程池(面试重点)
定时器
public static void main(String[] args) { Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { System.out.println(Thread.currentThread().getName() + "执行一次!"); } }, 3000, 2000); }
public static void main(String[] args) { ScheduledExecutorService pool = Executors.newScheduledThreadPool(3); pool.scheduleAtFixedRate(new TimerTask() { @Override public void run() { System.out.println(Thread.currentThread().getName() + "执行AAA!"); } }, 0, 2, TimeUnit.SECONDS); pool.scheduleAtFixedRate(new TimerTask() { @Override public void run() { System.out.println(Thread.currentThread().getName() + "执行BBB!"); } }, 0, 2, TimeUnit.SECONDS); }
线程的生命周期
- 继承Thread类
-
网络编程
网络通信
(1)IP地址
(2)端口号
(3)协议
UDP通信
实现一发一收 client(客户端) public static void main(String[] args) throws Exception{ // 创建发送端对象,发送端自带默认端口号 DatagramSocket socket = new DatagramSocket(); // 创建发送内容 byte[] data = "hello, 我是你爹!".getBytes(); DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getLocalHost(), 6666); // 发送数据 socket.send(packet); // 关闭端口 socket.close(); } server(服务端) public static void main(String[] args) throws Exception{ // 创建接收端对象 DatagramSocket socket = new DatagramSocket(6666); // 创建接收容器 byte[] data = new byte[1024 * 64]; DatagramPacket packet = new DatagramPacket(data, data.length); // 等待接收数据 socket.receive(packet); // 获取客户端信息 String ip = packet.getAddress().toString(); int port = packet.getPort(); System.out.println("获取来自ip:" + ip.substring(1, ip.length()) + ",端口:" + port + "的信息!"); // 取出数据 // 读多少,取多少 int length = packet.getLength(); String s = new String(data, 0, length); // 关闭端口 socket.close(); }
实现多发多收 client(客户端) public static void main(String[] args) throws Exception{ // 创建发送端对象,发送端自带默认端口号 DatagramSocket socket = new DatagramSocket(); // 获取键盘输入内容 Scanner scan = new Scanner(System.in); String content = scan.next(); while (true) { // 创建发送内容 byte[] data = content.getBytes(); DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getLocalHost(), 6666); // 发送数据 socket.send(packet); if (content.equals("exit")) { break; } content = scan.next(); } socket.close(); scan.close(); } server(服务端) public static void main(String[] args) throws Exception{ // 创建接收端对象 DatagramSocket socket = new DatagramSocket(6666); // 创建接收容器 byte[] data = new byte[1024 * 64]; DatagramPacket packet = new DatagramPacket(data, data.length); while(true) { // 等待接收数据 socket.receive(packet); String content = packet.getData().toString(); if(content.equals("exit")) { break; } // 获取客户端信息 String ip = packet.getAddress().toString(); int port = packet.getPort(); System.out.println("获取来自ip:" + ip.substring(1, ip.length()) + ",端口:" + port + "的信息!"); // 取出数据 // 读多少,取多少 int length = packet.getLength(); String s = new String(data, 0, length); System.out.println(s); } socket.close(); }
TCP通信
public static void main(String[] args) { try { // 创建Socket通信管道,请求有服务端的连接 Socket socket = new Socket("127.0.0.1", 6666); // 从Socket管道中获取字节输出流,负责发送数据 OutputStream os = socket.getOutputStream(); // 把低级的字节流包装成打印流 PrintStream ps = new PrintStream(os); // 发送消息 ps.println("hello啊!"); ps.flush(); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { try { // 注册端口 ServerSocket server = new ServerSocket(6666); // 必须调用accept方法,等待客户端的socket请求,建立socket通信 Socket socket = server.accept(); // 获取输入流 InputStream is = socket.getInputStream(); // 封装成缓冲字符流 BufferedReader br = new BufferedReader(new InputStreamReader(is)); // 读取数据 String msg; if((msg = br.readLine()) != null) { System.out.println(socket.getRemoteSocketAddress() + ":" + msg); } } catch (Exception e) { e.printStackTrace(); } }
解决方法: 使用多线程,并使用线程池进行优化client(客户端) public static void main(String[] args) { try { // 创建Socket通信管道,请求有服务端的连接 Socket socket = new Socket("127.0.0.1", 6666); // 从Socket管道中获取字节输出流,负责发送数据 OutputStream os = socket.getOutputStream(); // 把低级的字节流包装成打印流 PrintStream ps = new PrintStream(os); Scanner scan = new Scanner(System.in); while (true) { String msg = scan.nextLine(); // 发送消息 ps.println(msg); ps.flush(); } } catch (Exception e) { e.printStackTrace(); } } server(服务端) // 使用线程池进行优化 private static ExecutorService pools = new ThreadPoolExecutor(3, 5, 5, TimeUnit.SECONDS, new ArrayBlockingQueue<>(2), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); public static void main(String[] args) { try { // 注册端口 ServerSocket server = new ServerSocket(6666); while (true) { // 必须调用accept方法,等待客户端的socket请求,建立socket通信 Socket socket = server.accept(); // 使用线程池进行优化 MyThreadReader runnable = new MyThreadReader(socket); pools.execute(runnable); } } catch (Exception e) { e.printStackTrace(); } }
TCP通信实战案例-即时通信
client(客户端) public class Client3 { public static void main(String[] args) { try { // 创建Socket通信管道,请求有服务端的连接 Socket socket = new Socket("127.0.0.1", 6666); // 创建一个独立的线程用于接收服务端发来的消息 new Thread(new ClientRunnable(socket)).start(); // 从Socket管道中获取字节输出流,负责发送数据 OutputStream os = socket.getOutputStream(); // 把低级的字节流包装成打印流 PrintStream ps = new PrintStream(os); // 发送数据 Scanner scan = new Scanner(System.in); while (true) { String msg = scan.nextLine(); // 发送消息 ps.println(msg); ps.flush(); } } catch (Exception e) { e.printStackTrace(); } } } class ClientRunnable implements Runnable { private Socket socket; public ClientRunnable(Socket socket) { super(); this.socket = socket; } @Override public void run() { try { // 获取输入流 InputStream is = socket.getInputStream(); // 封装成缓冲字符流 BufferedReader br = new BufferedReader(new InputStreamReader(is)); // 读取数据 String msg; while ((msg = br.readLine()) != null) { System.out.println("收到消息:" + msg); } } catch (Exception e) { System.out.println(socket.getRemoteSocketAddress() + "下线了!"); } } } server(服务端) public class Server3 { public static ArrayList<Socket> allOnlineSockets = new ArrayList<Socket>(); public static void main(String[] args) { try { // 注册端口 ServerSocket server = new ServerSocket(6666); while (true) { // 必须调用accept方法,等待客户端的socket请求,建立socket通信 Socket socket = server.accept(); allOnlineSockets.add(socket); new Thread(new MyRunnable(socket)).start(); } } catch (Exception e) { e.printStackTrace(); } } } class MyRunnable implements Runnable { private Socket socket; public MyRunnable(Socket socket) { super(); this.socket = socket; } @Override public void run() { try { // 获取输入流 InputStream is = socket.getInputStream(); // 封装成缓冲字符流 BufferedReader br = new BufferedReader(new InputStreamReader(is)); // 读取数据 String msg; while ((msg = br.readLine()) != null) { System.out.println(socket.getRemoteSocketAddress() + "发来了:" + msg); // 转发信息 sendMsgTOAll(msg); } } catch (Exception e) { System.out.println(socket.getRemoteSocketAddress() + "下线了!"); } } private void sendMsgTOAll(String msg) throws Exception{ for(Socket socket: Server3.allOnlineSockets) { PrintStream ps = new PrintStream(socket.getOutputStream()); ps.println(msg); ps.flush(); } } }
-
Junit单元测试
-
反射
获取构造器 public static void main(String[] args) throws Exception { // 获取类对象 Class c = Student.class; // 获取Constructor对象 // 该方法只能拿public的 Constructor[] c1 = c.getConstructors(); for (Constructor constructor : c1) { System.out.println(constructor.getName() + "=====>" + constructor.getParameterCount()); } // 该方法可以拿所有的构造器 Constructor[] c2 = c.getDeclaredConstructors(); for (Constructor constructor : c2) { System.out.println(constructor.getName() + "=====>" + constructor.getParameterCount()); } // 获取某个构造器,只能拿public Constructor<Student> c3 = c.getConstructor(String.class, int.class); System.out.println(c3); // 获取某个构造器,全部可以拿 Constructor<Student> c4 = c.getDeclaredConstructor(); System.out.println(c4); // 如果遇到了私有构造器可以暴力反射 c4.setAccessible(true); Student s = c4.newInstance(); System.out.println(s); } 获取变量 public static void testFields() throws Exception { Class c = Student.class; Field[] fields = c.getFields(); for (Field field : fields) { System.out.println(field.getName() + "=====>" + field.getType()); } Constructor<Student> constructor = c.getDeclaredConstructor(); constructor.setAccessible(true); Field ageF = c.getDeclaredField("age"); Field ageN = c.getDeclaredField("name"); ageF.setAccessible(true); ageN.setAccessible(true); Student student = constructor.newInstance(); ageF.set(student, 30); ageN.set(student, "韩信"); System.out.println(student); int age = (int) ageF.get(student); String name = (String) ageN.get(student); System.out.println(name + ":" + age); } 获取方法 public static void testMethods() throws Exception { Class c = Student.class; Method[] methods = c.getDeclaredMethods(); for (Method method : methods) { System.out.println(method.getReturnType() + "=====" + method.getName()); } Method method = c.getDeclaredMethod("getName"); Student student = new Student("韩信", 20); method.setAccessible(true); System.out.println(method.invoke(student)); } 强行向Integer类型的ArrayList添加String类型数据 public static void testList() throws Exception{ List<Integer> list = new ArrayList<>(); list.add(22); list.add(11); list.add(33); Class c = list.getClass(); Method method = c.getDeclaredMethod("add", Object.class); method.invoke(list, "hello"); System.out.println(list); }
-
注解
-
动态代理
-
XML知识
约束文档
XML解析
XML文件的信息检索技术:XPath
-
装饰设计模式