Java基础复习10:Java网络编程入门、Junit单元测试、反射基本介绍、注解基本介绍、XML基本介绍

目录

一、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文档约束

可以约束到具体的数据类型 了解即可



不需要自己写 只要遵守别人已经写好的约束文档即可

相关推荐
runningshark2 小时前
【Linux】Virtualbox 中如何给Ubuntu扩容
笔记·学习
user_admin_god2 小时前
Opencode常见问题与优化排查
java·人工智能·自然语言处理·nlp·idea
工作log2 小时前
从 Ubuntu 22.04 到 ROS 2 Humble 完整环境搭建与 Java 控制指南
java·linux·ubuntu
Wenzar_2 小时前
**元宇宙经济中的智能合约与数字资产:基于Solidity的NFT交易平台开发实践**随着元宇宙概念持续升
java·python·区块链·智能合约
Giggle12182 小时前
从零解构一套校园外卖系统:架构设计、技术选型与核心难点剖析
java·运维·微服务
一叶飘零_sweeeet2 小时前
Spring Boot 4.0:云原生 Java 开发的范式革命
java·spring boot·云原生
Devin~Y2 小时前
大厂 Java 面试实战:Spring Boot 微服务 + Redis 缓存 + Kafka 消息 + Kubernetes + RAG(小Y水货翻车记)
java·spring boot·redis·kafka·spring security·jwt·oauth2
朱一头zcy2 小时前
设计模式入门:简单认识单例模式、模板方法、工厂模式、装饰模式、动态代理
java·设计模式
日拱一卒的小田2 小时前
ZYNQ学习笔记1-裸机-PS端中断配置、IO配置及PS/PL AXI交互(2-2)
笔记·学习·microsoft