目录
- 一、Java网络编程入门
-
- [1.1 网络编程三要素](#1.1 网络编程三要素)
- [1.2 InetAddress常用API](#1.2 InetAddress常用API)
- [1.3 TCP](#1.3 TCP)
- [1.4 UDP](#1.4 UDP)
- 二、Junit单元测试
- 三、反射基本介绍
-
- [3.1 概述](#3.1 概述)
- [3.2 反射获取类对象](#3.2 反射获取类对象)
- [3.3 反射获取构造器对象](#3.3 反射获取构造器对象)
- [3.4 反射获取成员变量对象](#3.4 反射获取成员变量对象)
- [3.5 反射获取成员方法对象](#3.5 反射获取成员方法对象)
- [3.6 运行阶段为泛型集合添加任意类型的元素](#3.6 运行阶段为泛型集合添加任意类型的元素)
- [3.7 反射案例](#3.7 反射案例)
- 四、注解基本介绍
-
- [4.1 自定义注解](#4.1 自定义注解)
- [4.2 元注解](#4.2 元注解)
- [4.3 注解解析](#4.3 注解解析)
- 五、XML基本介绍
-
- [5.1 概述](#5.1 概述)
- [5.2 语法规则](#5.2 语法规则)
- [5.3 了解DTD文档约束](#5.3 了解DTD文档约束)
- [5.4 了解schema文档约束](#5.4 了解schema文档约束)
一、Java网络编程入门
1.1 网络编程三要素
通过IP定位网络设备 通过端口号定位具体的进程(应用程序)
网络传输协议制定数据传输规则
IPv4:
IPv6:
不同设备上 同一个进程(应用程序)的端口号 也应该是一致的
TCP/IP协议
1.2 InetAddress常用API
注意返回值
注意是否是静态方法
1.3 TCP
特点
通信效率相对较低 但是可靠传输
三次握手可以确保:
1.客户端发消息 收消息没问题
2.服务端发消息 收消息没问题
四次挥手确保数据都传输完毕 再断开连接
一个客户端和一个服务端通信
客户端(发送端):
服务端(接收端):
如果想实现一个客户端发送多条消息 可以把部分代码放入死循环客户端:
服务端:
多个客户端和一个服务端通信
1.2的代码 服务端本质上都是单线程的 一次只能和一个客户端建立连接
所以每次只能收到一个客户端发送的消息(即使打开多个客户端向服务端发送消息)
改进:
1.主线程循环和客户端建立连接 拿到每个启动的客户端的Socket管道连接
2.每次拿到一个Socket通信管道 就分配一个子线程去处理
子线程任务代码:每次关闭一个客户端 连接断开 服务端就会抛出一个对应的reset异常
把这个因为客户端下线的异常捕获 就能追踪下线的客户端
服务端:
客户端:
线程池优化上一个代码
一个连接 → 对应一个子线程 不合理
用线程池管理连接 提高性能
客户端不需要修改 服务端处理的时候利用线程池:注意 下图红字更准确来说:
是把socket交给任务对象 重写run指定这个socket需要完成的任务 然后再把这个任务交给线程池处理
任务代码:
再次理解线程池流程:
客户端→服务端→其它多个客户端
1.客户端不仅需要发消息 也会收到其他客户端的消息(利用一下服务端的线程池pool)
2.服务端接收到某个客户端的消息 需要群发给其他客户端→要保存每个客户端连接的socket管道
3.群发就是服务端对应的那个任务 遍历保存的每个客户端socket 把接收到消息发出去
服务端任务代码:
java
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
public class MyRunnable implements Runnable {
private Socket socket;
public MyRunnable(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
InputStream inputStream = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
String inputLine;
while ((inputLine = br.readLine()) != null) {
System.out.println(socket.getRemoteSocketAddress()
+ "客户端向你发送: " + inputLine);
List<Socket> list = test.onlineClient;
for (Socket socket1 : list) {
new PrintStream(socket1.getOutputStream()).println(inputLine);
}
}
} catch (Exception e) {
System.out.println(socket.getRemoteSocketAddress() + "客户端下线了");
test.onlineClient.remove(socket);
}
}
}
服务端代码:
java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
public class test {
public static List<Socket> onlineClient = new ArrayList<Socket>();
public static ExecutorService pool = new ThreadPoolExecutor(
2, 3
, 10, TimeUnit.SECONDS
, new ArrayBlockingQueue<>(1)
, Executors.defaultThreadFactory()
, new ThreadPoolExecutor.AbortPolicy());
public static void main(String[] args) throws Exception {
System.out.println("====服务端启动===");
ServerSocket serverSocket = new ServerSocket(7777);
while (true) {
//每次等待到一个连接 拿到一个socket对象 就交给子线程处理
Socket socket = serverSocket.accept();
System.out.println(socket.getRemoteSocketAddress() + "客户端上线了");
onlineClient.add(socket);
Runnable target = new MyRunnable(socket);
pool.execute(target);
}
}
}
客户端代码:
java
import java.io.*;
import java.net.Socket;
import java.util.List;
import java.util.Scanner;
public class test01 {
public static void main(String[] args) throws Exception {
System.out.println("====客户端启动===");
Socket socket = new Socket("127.0.0.1", 7777);
test.pool.execute(new ClinetRunnable(socket));
OutputStream os = socket.getOutputStream();
PrintStream ps = new PrintStream(os);
Scanner sc = new Scanner(System.in);
String input;
while (true) {
System.out.println("发送:");
input = sc.nextLine();
ps.println(input);
ps.flush();
}
}
}
class ClinetRunnable implements Runnable {
private Socket socket;
public ClinetRunnable(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
InputStream inputStream = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
String inputLine;
while ((inputLine = br.readLine()) != null) {
System.out.println(socket.getRemoteSocketAddress()
+ "客户端发送: " + inputLine);
}
} catch (Exception e) {
System.out.println("你被T了");
}
}
}
1.4 UDP
特点
有一个目的地 带着数据包发出去即可 不管数据是否被接收
实现一发一收
客户端发送 数据包→服务端
数据包:/**
public DatagramPacket(byte buf[], int length,InetAddress address, int port)
参数一:封装要发送的数据
参数二:发送数据的大小(字节数)
参数三:接收端(服务端)的IP地址
参数四:接收端(服务端)的端口
*/
发送端(客户端):
接收端(服务端):socket.receive(packet);会把接到的数据放到buffer
实现多发多收
客户端(发送端):
服务端(接收端):
IDEA开启多个客户端:UDP接收端只负责接受数据包 无所谓是哪个发送端发来的 所以可以接收多个客户端的数据
广播与组播
实现广播:
实现组播:
二、Junit单元测试
1.测试方法必须是公共的 无参数的 无返回值的非静态方法(即实例方法) 如public void testLoginName(){ }
2.需要有@Test注解
3.一个业务方法 对应一个测试方法
4.测试方法如果有返回值 可以用断言进行预期结果测试
可以一键跑完当前模块的所有测试方法
比如测试方法需要一些IO流/静态资源 可以用这些注解进行初始化或者释放资源
三、反射基本介绍
3.1 概述
运行时 获取 字节码文件对象 → 进而解析类中的成分
3.2 反射获取类对象
对象.getClass()是Object超类提供的方法 任何一个对象都可以调用
3.3 反射获取构造器对象
注意有些方法只能拿到public修饰的构造器对象
获取构造器对象之后 进一步创建对象
3.4 反射获取成员变量对象
获取全部成员变量:getDeclaredFields()
获取某个成员变量:getDeclaredField(属性名称)
拿到成员变量对象之后 为当前成员变量对象所对应的对象赋值成员变量对象是不能孤立存在的 它也属于某个具体对象
3.5 反射获取成员方法对象
获取成员方法对象
获取成员方法对象之后 执行此方法成员方法对象本身提供了一个方法
Object invoke(Object obj, Object... args)参数一:触发的是哪个对象的方法执行
可变参数二: 调用方法时传递的实际参数(如果是无参 那就不写)
3.6 运行阶段为泛型集合添加任意类型的元素
javac.exe→class文件进入运行阶段的时候 集合的泛型会自动擦除
但是运行阶段 通过反射 又能获取到集合的类对象 进而获得它的成员方法对象add 然后add.invoke
3.7 反射案例
由于不知道具体是什么类 也不确定该类到底有什么属性 → 反射可以做到
参考代码:
四、注解基本介绍
4.1 自定义注解
注解:简单来说就是做一个标记 然后特殊处理
特殊属性value
4.2 元注解
元注解:注解 (自定义)注解 的 注解
4.3 注解解析
判断有没有解析注解的能力
就是看有没有实现AnnotatedElement接口
要解析XXX成分上的注解 → 就先拿到该成分的成分对象(比如类对象 成员方法对象)
案例参考代码:
java
public class AnnotationDemo3 {
@Test
public void parseClass() {
// 先得到类对象
Class c = BookStore.class;
// 判断这个类上面是否存在Bookk这个注解
if (c.isAnnotationPresent(Bookk.class)) {
// 直接获取该注解对象 这里不用多态了 因为要拿注解的特有属性
//Annotation book = c.getAnnotation(Bookk.class);
Bookk book = (Bookk) c.getDeclaredAnnotation(Bookk.class);
System.out.println(book.value());
System.out.println(book.price());
System.out.println(Arrays.toString(book.author()));
}
}
@Test
public void parseMethod() throws NoSuchMethodException {
Class c = BookStore.class;
Method m = c.getDeclaredMethod("test");
if (m.isAnnotationPresent(Bookk.class)) {
Bookk book = (Bookk) m.getDeclaredAnnotation(Bookk.class);
System.out.println(book.value());
}
}
}
@Bookk(value = "《情深深雨濛濛》", price = 99.9, author = {"琼瑶"})
class BookStore {
@Bookk(value = "《三少爷的剑》", price = 399.9, author = {"古龙", "熊耀华"})
public void test() {
}
}
五、XML基本介绍
5.1 概述
1.数据的存储/传输
2.作为配置文件
5.2 语法规则
1.文档声明必须在第一行 表示这个文件是一个xml文件
2.根标签必须有 且只能有一个
3.注意比如<这些特殊字符
标签规则:
一些特殊字符:
5.3 了解DTD文档约束
作用:约束XML文件的编写格式 但是不能约束具体的数据类型 比如下图的售价可以写成字符串
了解即可 几乎不会自己手写文档约束 拿来用就行
5.4 了解schema文档约束
可以约束到具体的数据类型 了解即可
不需要自己写 只要遵守别人已经写好的约束文档即可






























































































