小黑子—Java从入门到入土过程:第十一章 - 网络编程、反射及动态代理

Java零基础入门11.0

  • 网络编程
    • 1. 初识网络编程
    • 2. 网络编程三要素
    • 3.IP三要素
      • 3.1 IPV4的细节
        • 3.1.1特殊的IP地址
        • 3.1.2 常用的CMD命令
      • 3.2 InetAddress 的使用
      • 3.3 端口号
      • 3.4 协议
        • 3.4.1 UDP协议
          • 3.4.1 - I UDP 发送数据
          • 3.4.1 - II UDP 接收数据
          • 3.4.1 - III UDP 练习(聊天室)
        • 3.4.2 UDP的三种通信方式
        • 3.4.3 TCP协议
          • 3.4.3 - I TCP 发送和接收数据
          • 3.4.3 - II TCP 中文乱码问题
          • 3.4.3 - III TCP 代码细节
        • 3.4.4 TCP通信程序
          • 3.4.4 - I 三次挥手
          • 3.4.4 - II 四次挥手
    • 4. 综合练习
      • 4.1 多发多收
      • 4.2 接收并反馈
      • 4.3 上传文件
      • 4.4 文件名重复
      • 4.5 多线程版的服务端上传文件
      • 4.6 线程池的服务端
      • 4.7 BS架构模型
  • 反射
    • 5. 初识反射
    • 6. 获取class对象的三种方式
    • 7. 反射获取构造方法
    • 8. 反射获取成员变量
    • 9. 反射获取成员方法
    • 10. 综合练习
      • 10.1 保存信息
      • 10.2 跟配置文件结合动态创建
  • 动态代理
    • 11. 动态代理的思想分析
    • 12. 动态代理的代码实现

网络编程

1. 初识网络编程

在这里插入图片描述
Java中可以使用java.net包下的技术秦颂开发出常见的网络应用程序。

常见的软件架构:bs和cs
在这里插入图片描述

在这里插入图片描述
BS架构:
在这里插入图片描述
优点:
在这里插入图片描述
缺点:
在这里插入图片描述

CS架构:
在这里插入图片描述
优点:
在这里插入图片描述

缺点:
在这里插入图片描述
小结:
在这里插入图片描述

2. 网络编程三要素

1、确定对方电脑在互联网上的地址(IP)
在这里插入图片描述

2、确定接收数据的软件(端口号)
一个端口号只能被一个软件绑定使用
在这里插入图片描述

3、确定网络传输的规则(协议)
在这里插入图片描述

IP:

  • 设备在网络中的地址,是唯一的标识 端口号:应用程序在设备中唯一的标识(设备包括电脑、笔记本、手机等)

协议:

  • 数据在网络中传输的规则,常见的

协议:

  • 数据在网络传输的规则,常见的协议有UDP、TCP、http、ftp

小结:
在这里插入图片描述

3.IP三要素

IP:
在这里插入图片描述

IPV4:
在这里插入图片描述
IPV6:
在这里插入图片描述
在这里插入图片描述
小结:

在这里插入图片描述

3.1 IPV4的细节

在这里插入图片描述
比如:

在网吧里面的很多台电脑,不是都在连接外网的时候都有一个公网的IP,它们往往是共享同一个公网IP,再由路由器给每一台电脑分配局域网IP,这样就可以实现节约IP的效果
在这里插入图片描述

3.1.1特殊的IP地址

  • 127.0.0.1,也就是localhost:是回送地址也称本地回环地址,也称本机IP,永远只会寻找当前所在本机

提问:

假设192.168.1.100是我电脑的IP,那么这个IP跟127.0.0.1是一样的吗?
不一样

案例:

  1. 现在以192.168.1.100发送数据的时候,此时是先发到路由器,路由器再找到你当前的IP,这样子才能实现数据的发送,但是此时会有个小细节——每一个路由器给你分配的IP是不一样的

所以在不同的地方上网,局域网IP有可能会不一样
在这里插入图片描述

  1. 如果要往127.0.0.1发送数据,是不经过路由器的,数据在经过网卡的时候,网卡会发现要往127.0.0.1发送就会直接把这个数据给自己发送回来
    在这里插入图片描述

3.1.2 常用的CMD命令

ipconfig:查看本机IP地址
在这里插入图片描述

ping:检查网络是否连通

这里是引用
小结:
在这里插入图片描述

3.2 InetAddress 的使用

此类表示互联网协议(IP)地址

   public static void main(String[] args) throws IOException {
        //获取InetAddress的对象
        //IP的对象 一台电脑的对象
        InetAddress address = InetAddress.getByName("Javris");
        System.out.println(address);

        String name = address.getHostName();
        System.out.println(name);

        String ip = address.getHostAddress();
        System.out.println(ip);
    }

3.3 端口号

在这里插入图片描述
端口说白了就可以理解成为——电脑往外发送数据或者是接收数据的出口or入口

案例:
电脑A向电脑B发送数据
在这里插入图片描述

3.4 协议

在这里插入图片描述
OSI模型:
在这里插入图片描述

TCP/IP模型:

在该模型当中把OSI的应用层、表示层、会话层给合并了——应用层,最后两层数据链路层、物理层合并了——物理链路层
在这里插入图片描述

3.4.1 UDP协议

在这里插入图片描述
面向无连接什么意思?
假设左边的电脑要给右边的电脑发送数据,在发送数据之前按道理来讲,要先检查两台电脑之间的网络是否畅通。但是,UDP协议是不会检查的,能收到就收到,收不到就算了
在这里插入图片描述
应用场景:适用于丢一点数据,也不会产生影响的情况。比如:网络会议、语音通话、看视频

3.4.1 - I UDP 发送数据

在这里插入图片描述
在这里插入图片描述

    public static void main(String[] args) throws IOException {
        DatagramSocket ds = new DatagramSocket();

        //打包数据
        String s1 = "李在赣神魔?";
        byte[] bytes = s1.getBytes();

        InetAddress address = InetAddress.getByName("127.0.01");
        //端口
        int port = 10086;

        DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);

        ds.send(dp);
        ds.close();
    }

程序运行完毕,控制台没有消息是因为UDP的特点:不管你接不接得到,发了就行

3.4.1 - II UDP 接收数据

在这里插入图片描述
接收数据的时候只要给它传递一个数组就可以了
在这里插入图片描述

注意:在运行的时候要先运行接收端,再运行发送端

发送端:

public class Test1 {
    public static void main(String[] args) throws IOException {
        //创建DatagramSocket对象
        //细节:
        //绑定端口:以后我们就是通过这个端口往外发送
        //空参:所有可用的端口中随机一个进行使用
        //有参:指定端口号进行绑定
        DatagramSocket ds = new DatagramSocket();

        //打包数据
        String s1 = "李在赣神魔?";
        byte[] bytes = s1.getBytes();

        InetAddress address = InetAddress.getByName("127.0.01");
        //端口
        int port = 10086;

        DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);

        ds.send(dp);
        ds.close();
    }
}

接收端:

public class Test2 {
    public static void main(String[] args) throws IOException {
        //1.创建DatagramSocker对象
        //细节:
        //在接收的时候,一定要绑定端口
        //而且绑定的端口一定要跟发送的端口保持一致

        DatagramSocket ds = new DatagramSocket(10086);

        //2.接收数据包
        byte[] bytes = new byte[1024];
        DatagramPacket dp = new DatagramPacket(bytes,bytes.length);//后者是用多大的空间去接收数据
        //相当于在接收数据的时候,还是把这个数据放到bytes这个数组里面

		//该方法是阻塞的
		//程序执行到这一步的时候,会在这里等死
		//等发送端发送消息
        ds.receive(dp);

        //3.解析数据	包
        //获取包的数据、长度、地址、端口
        byte[] data = dp.getData();
        int len = dp.getLength();
        InetAddress address = dp.getAddress();
        int port = dp.getPort();

        System.out.println("接收到数据"+new String(data,0,len));
        System.out.println("该数据是从"+address+"这台电脑"+"port"+"端口发出的");

        //4.释放资源
        ds.close();

    }
}

在这里插入图片描述

3.4.1 - III UDP 练习(聊天室)

在这里插入图片描述
修改IDEA设置:
在发送端选择编辑7
在这里插入图片描述
修改选项
在这里插入图片描述
勾选多个实例:
一定要勾选,不然没法同时运行多个
在这里插入图片描述

接收端:

    public static void main(String[] args) throws IOException {
        //创建对象接收端口
        DatagramSocket ds = new DatagramSocket(10086);

        //接收数据包,用数组
        byte[] bytes = new byte[1024];//为什么该数组和数据包不写入循环里面呢?
        // 因为每一次都拿同一个数组去接收数据,第二次可以把第一次的覆盖
        DatagramPacket dp = new DatagramPacket(bytes, bytes.length);

        while (true){
            ds.receive(dp);
            //解析数据包
            byte[] data = dp.getData();
            int len = dp.getLength();
            String ip = dp.getAddress().getHostAddress();
            String name = dp.getAddress().getHostName();

            //打印
            System.out.println("IP为:"+ip+",主机民为"+name+"的人,发送了数据"+new String(data,0,len));
        }
    }

发送端:
发送端设置完成了之后,可以运行多个

   public static void main(String[] args) throws IOException {
        DatagramSocket ds = new DatagramSocket();//相当于一个快递公司,其不肯能进行循环

        //输入数据,进行打包
        Scanner sc = new Scanner(System.in);
        //下面的快递可以无休止地进行循环
        while(true){
            System.out.println("请输入想要说出的话:");
            String str = sc.nextLine();
            byte[] bytes = str.getBytes();
            if("886".equals(str)){
                break;
            }
            //建立地址、端口,然后打包进去
            InetAddress address = InetAddress.getByName("127.0.01");
            int port = 10086;
            DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, port);

            //3.发送数据
            ds.send(dp);
        }

        //4.释放资源
        ds.close();
    }

在这里插入图片描述

3.4.2 UDP的三种通信方式

单播、组播和广播

1、单播
一对一
以前的代码就是单播
在这里插入图片描述

2、组播
一对多(一组)、
组播地址:224.0.0.0~239.255.255.255
其中224.0.0.0~224.0.0.255为预留的组播地址
在这里插入图片描述

3、广播
一对全(全部)
广播地址:255.255.255.255

在这里插入图片描述

3.4.3 TCP协议

在这里插入图片描述
它在发数据的时候,会先去检查两台电脑之间的网络是否畅通,就是确保连接成功才会发送数据——面向连接
在这里插入图片描述
应用场景:下载软件、文字聊天、发送邮件

package socketnet.Dome4;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;

public class dome2 {
    public static void main(String[] args) throws IOException {
        MulticastSocket ms = new MulticastSocket();

        //打包数据
        String str = "你好啊。。。";
        byte[] bytes = str.getBytes();
        //发送的地址
        InetAddress address = InetAddress.getByName("224.0.0.1");
        //要发送的端口号
        int port = 10000;

        DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);
        //发送数据
        ms.send(dp);
        //释放资源
        ms.close();
    }
}
package socketnet.Dome4;

import java.io.IOException;
import java.net.*;

public class dome1 {
    public static void main(String[] args) throws IOException {
        MulticastSocket ms = new MulticastSocket(10000);

        //将当前主机,添加到224.0.0.1的这一组当中
        InetAddress address = InetAddress.getByName("224.0.0.1");
        ms.joinGroup(address);

        //接收数据包
        byte[] bytes = new byte[1024];
        DatagramPacket dp = new DatagramPacket(bytes, bytes.length);

        //该方法是堵塞的
        //程序执行到这一步的时候,会在这里死等
        //等发送端发送消息
        ms.receive(dp);

        //解析数据包
        byte[] data = dp.getData();
        int len = dp.getLength();
        int port = dp.getPort();

        System.out.println("接收到的数据"+new String(data,0,len));
        System.out.println("该数据是从"+address+"这台电脑中的"+port+"这个端口发出的");

        //释放资源
        ms.close();
    }
}
package socketnet.Dome4;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;

public class dome {
    public static void main(String[] args) throws IOException {
        MulticastSocket ms = new MulticastSocket(10000);

        //将当前主机,添加到224.0.0.1的这一组当中
        InetAddress address = InetAddress.getByName("224.0.0.1");
        ms.joinGroup(address);

        //接收数据包
        byte[] bytes = new byte[1024];
        DatagramPacket dp = new DatagramPacket(bytes, bytes.length);

        //该方法是堵塞的
        //程序执行到这一步的时候,会在这里死等
        //等发送端发送消息
        ms.receive(dp);

        //解析数据包
        byte[] data = dp.getData();
        int len = dp.getLength();
        int port = dp.getPort();

        System.out.println("接收到的数据"+new String(data,0,len));
        System.out.println("该数据是从"+address+"这台电脑中的"+port+"这个端口发出的");

        //释放资源
        ms.close();
    }
}

package socketnet.Dome5;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;

public class dome {
    public static void main(String[] args) throws IOException {
        MulticastSocket ms = new MulticastSocket();

        //打包数据
        String str = "你好啊。。。";
        byte[] bytes = str.getBytes();
        //发送的地址
        InetAddress address = InetAddress.getByName("255.255.255.255");
        //要发送的端口号
        int port = 10000;

        DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);
        //发送数据
        ms.send(dp);
        //释放资源
        ms.close();
    }
}

3.4.3 - I TCP 发送和接收数据

TCP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket对象
通信之前要保证连接已经建立
通过Socket产生IO流来进行网络通信
在这里插入图片描述

在这里插入图片描述
客户端(Socket)

  1. 创建客户端的Socket对象(Socket)与指定服务端连接
    Socket(String host , int port)
  2. 获取输出流,写数据
    OutputStream getOutputstream()
  3. 释放资源
    void close

服务器(ServerSocket)

  1. 创建服务器端的Socket对象(ServerSocket)
    ServerSocket(int port)

  2. 监听客户端连接,返回一个Socket对象
    Socket accept()

  3. 获取输入流,读数据,并把数据显示在控制台
    InputStreamReader getInputStreamReader(socket.getInputStream )

  4. 释放资源
    void close

先来运行服务端(接收的):

   public static void main(String[] args) throws IOException {
        //TCP协议,接收数据
        //1.创建 ServerSocker对象
        ServerSocket ss = new ServerSocket(1000);
        //2.监听客户端的链接
        Socket socket = ss.accept();

        //3.从连接通道中获取输入流读取数据
        InputStream is = socket.getInputStream();
        int b ;
        while((b=is.read())!=-1){
            System.out.println((char) b);
        }

        socket.close();
        ss.close();


    }

再运行客户端(发送的):

    public static void main(String[] args) throws IOException {
     //TCP协议,发送数据

        //1.创建Socket对象
        //细节:在创建对象的同时会连接服务器
        //      如果连接不上,代码会报错
        Socket socket = new Socket("127.0.01",1000);
        //2.可以从连接通道中获取输出流
        OutputStream os = socket.getOutputStream();
        os.write("aaa".getBytes());//这种方式不能传中文

        //3.释放资源
        os.close();
        socket.close();
    }

在这里插入图片描述

3.4.3 - II TCP 中文乱码问题

为什么会出现乱码问题呢?
在这里插入图片描述
在使用IDEA默认的编码表(UTF-8),此时就会把一个中文变成3个字节,服务器在读的时候是一个字节一个字节地读,所以每次转码的时候只是1/3个中文,造成了乱码

解决方案:

  1. 不要拿InputStream字节流去读了,把其变成字符流InputStreamReader,就不会出现乱码
    在这里插入图片描述
  2. 如果说想要提高读取的效率,那么就再把字符流变成缓冲流BufferedReader
    在这里插入图片描述
3.4.3 - III TCP 代码细节

在这里插入图片描述

3.4.4 TCP通信程序

3.4.4 - I 三次挥手

在这里插入图片描述

3.4.4 - II 四次挥手

多了一次:需要保证已经把连接通道里面的数据处理完毕了,这个时候的连接才能断开
在这里插入图片描述

4. 综合练习

4.1 多发多收

在这里插入图片描述

   public static void main(String[] args) throws IOException {
        //服务器
        ServerSocket ss = new ServerSocket(10000);

        //等待客户端连接
        Socket socket = ss.accept();

        //读取数据
        InputStreamReader isr = new InputStreamReader(socket.getInputStream());
        int b;
        while((b=isr.read())!=-1){
            System.out.print((char)b);
            
        }

        socket.close();
        ss.close();
    }
    public static void main(String[] args) throws IOException {
     //客户端
        Socket socket = new Socket("127.0.01", 10000);

        Scanner sc = new Scanner(System.in);
        OutputStream os = socket.getOutputStream();

        while(true){
            System.out.println("请输入信息:");
            String str = sc.nextLine();
            if("886".equals(str)){
                break;
            }
            os.write(str.getBytes());//getBytes(): 使用平台的默认字符集将字符串编码为 byte
        }

        os.close();
    }

在这里插入图片描述

4.2 接收并反馈

在这里插入图片描述
思路:
在这里插入图片描述

服务器:

   public static void main(String[] args) throws IOException {
        //服务器
        ServerSocket ss = new ServerSocket(10000);

        //等待客户端连接
        Socket socket = ss.accept();

        //socket中获取输入流读取数据
        InputStream is = socket.getInputStream();
        InputStreamReader isr = new InputStreamReader(is);
        int b;
        //细节:
        //read方法会从连接通道中读取数据
        //但是,需要有一个结束标记,此处的循环才会停止
        //否则,程序会一致停在reead方法这里,等待读取下面的数据
        while((b=isr.read())!=-1){
            System.out.println((char)b);
        }

        //回写数据
        String str = "乖乖站好";
        OutputStream os = socket.getOutputStream();
        os.write(str.getBytes());

        socket.close();
        ss.close();
    }

客户端:

   public static void main(String[] args) throws IOException {
     //客户端
        Socket socket = new Socket("127.0.01", 10000);

        //写出数据
        String str = "李在赣神魔?";
        OutputStream os = socket.getOutputStream();
        os.write(str.getBytes());
        //写出一个结束标记
        socket.shutdownOutput();


        //接收服务端回写的数据
        InputStream is = socket.getInputStream();
        InputStreamReader isr = new InputStreamReader(is);
        int b;
        while((b= isr.read())!=-1){
            System.out.println((char) b);
        }
        socket.close();
    }

在这里插入图片描述

4.3 上传文件

结合本地IO流与网络IO流结合起来
在这里插入图片描述
服务器:

    public static void main(String[] args) throws IOException {
        //服务器
        ServerSocket ss = new ServerSocket(10000);

        //等待客户端连接
        Socket socket = ss.accept();

        //读取数据并保存到本地文件当中
        BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("javaprogram1\\b.txt"));
        int len;
        byte[] bytes = new byte[1024];
        while((len=bis.read())!=-1){
            bos.write(bytes,0,len);
        }

        //回写数据
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        bw.write("上传成功");
        bw.newLine();
        bw.flush();

        socket.close();
        ss.close();

    }

客户端:

    public static void main(String[] args) throws IOException {
     //客户端
        Socket socket = new Socket("127.0.01", 10000);

        //读取本地文件中的数据,并写到服务器当中
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("javaprogram1\\a.txt"));
        BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
        byte[] bytes = new byte[1024];
        int len;
        while((len=bis.read())!=-1){
            bos.write(bytes,0,len);//在本地读了多少,就立马把多少数据写到客户端当中
        }
        //往服务器写出结束标记
        socket.shutdownOutput();

        //接受服务端的回写数据
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));//相当于就是先获取到连接通道里面的输入流,字节流->字符流->再用缓冲流进行包裹
        String line = br.readLine();//这个line就是服务器回写的数据
        System.out.println(line);

        socket.close();
    }

4.4 文件名重复

在这里插入图片描述
Java里面有个UUID类

  • 可以使用该类生成一个随机的文件名
  • 可以使用静态的randomUUID方法,返回一个UUID对象
    public static void main(String[] args) throws IOException {
        System.out.println(UUID.randomUUID());
        String str = UUID.randomUUID().toString().replace("-", "");//随机生成的UUID
        System.out.println(str);
    }

在这里插入图片描述
以此修改上方的服务端代码文件:

   public static void main(String[] args) throws IOException {
        //服务器
        ServerSocket ss = new ServerSocket(10000);

        //等待客户端连接
        Socket socket = ss.accept();

        //读取数据并保存到本地文件当中
        BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
        String name = UUID.randomUUID().toString().replace("-", "");
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("javaprogram1\\+"+name+"txt"));
        int len;
        byte[] bytes = new byte[1024];
        while((len=bis.read())!=-1){
            bos.write(bytes,0,len);
        }

        //回写数据
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        bw.write("上传成功");
        bw.newLine();
        bw.flush();

        socket.close();
        ss.close();

    }

在这里插入图片描述

4.5 多线程版的服务端上传文件

在这里插入图片描述
MyRunnable类:

public class MyRunnable implements Runnable{

    Socket socket;
    public MyRunnable(Socket socket){
        this.socket = socket;
    }

    //有一个问题里面原本是没有socket的,这时该怎么办?
    //当开启一条线程的时候,需要把客户端的连接对象传递给线程,那么就可以通过构造方法来传递
    @Override
    public void run() {
        try {
            //读取数据并保存到本地文件当中
            BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
            String name = UUID.randomUUID().toString().replace("-", "");
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("javaprogram1\\+" + name + "txt"));
            int len;
            byte[] bytes = new byte[1024];
            while ((len = bis.read()) != -1) {
                bos.write(bytes, 0, len);
            }

            //回写数据
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            bw.write("上传成功");
            bw.newLine();
            bw.flush();

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(socket!=null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

服务器:

    public static void main(String[] args) throws IOException {
        //服务器
        ServerSocket ss = new ServerSocket(10000);
        while (true){
            //等待客户端连接
            Socket socket = ss.accept();
            //开启一条线程
            //一个用户就对应服务端的一条线程
            new Thread(new MyRunnable(socket)).start();
        }

    }

4.6 线程池的服务端

在这里插入图片描述

    public static void main(String[] args) throws IOException {
       //创建线程池对象,7个参数,ctrl+p提示
        ThreadPoolExecutor pool = new ThreadPoolExecutor(
                3,//核心线程数量
                16,//线程池总大小
                60,//空闲时间
                TimeUnit.SECONDS,//单位空闲时间
                new ArrayBlockingQueue<>(2),//2个队列
                Executors.defaultThreadFactory(),//线程工厂,让线程池如何创建线程对象
                new ThreadPoolExecutor.AbortPolicy()//阻塞队列
        );

        //服务器
        ServerSocket ss = new ServerSocket(10000);
        while (true){
            //等待客户端连接
            Socket socket = ss.accept();
            //开启一条线程
            //一个用户就对应服务端的一条线程
//            new Thread(new MyRunnable(socket)).start();
            pool.submit(new MyRunnable(socket));
        }

    }

多次运行后:
在这里插入图片描述

4.7 BS架构模型

在这里插入图片描述

  • 运行该代码然后直接在浏览器中打开该网站
  • 打开网站之后会将数据返回到IDEA控制台中

比如:
运行服务端

   public static void main(String[] args) throws IOException {
        //创建对象绑定端口
        ServerSocket ss = new ServerSocket(10000);
        //等待客户端来连接
        Socket socket = ss.accept();
        //读取数据
        InputStreamReader is = new InputStreamReader(socket.getInputStream());

        int len;
        while ((len=is.read())!=-1){
            System.out.print((char) len);
        }
        socket.close();
        ss.close();
    }

在这里插入图片描述
在IDEA返回的数据:
在这里插入图片描述

反射

5. 初识反射

什么是反射?

反射允许对成员变量,成员方法和构造方法的信息进行编程访问
在这里插入图片描述
能把这个类扒的干干净净,一点都不剩
IDEA里面的提示功能就是个反射
在这里插入图片描述
利用反射就可以获取这个类里面的所有信息

问题:既然是从里面拿东西,为什么一定要有反射,用IO流不行吗?

IO流是从上往下一行一行地去读程序

  • 当读到构造方法和普通成员方法的时候很难进行区分
    在这里插入图片描述
  • 如果说想用返回值去区分,那么成员变量和局部变量应该无法去区分
    在这里插入图片描述
    那么反射要学什么东西呢?
    学习反射的获取和解剖
    在这里插入图片描述
    反射的作用:
    在这里插入图片描述

6. 获取class对象的三种方式

在这里插入图片描述

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //1.第一种方式,最为常用的
        //全类名:包名+类名
        Class<?> clazz1 = Class.forName("test6.Student");

        //2.第二种方式
        //一般更多的是当做参数进行传递
        Class clazz2 = Student.class;
        System.out.println(clazz1==clazz2);//true

        //3.第三种方式
        //当已经有了这个类的对象的时候,才可以进行时候
        Student stu = new Student();
        Class clazz3 = stu.getClass();
        System.out.println(clazz2==clazz3);//true
    }

7. 反射获取构造方法

在这里插入图片描述
student类:

public class Student {

    private static final long serialVersionUID = 650157805827481085L;
    private String name;
    private int age;
    private String address;


    public Student() {
    }

    public Student( String name, int age, String address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

    public Student(String name){
        this.name = name;
    }

    protected Student(int age){
        this.age = age;
    }

    private Student(String name,int age){
        this.name = name;
        this.age = age;
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }

    /**
     * 获取
     * @return address
     */
    public String getAddress() {
        return address;
    }

    /**
     * 设置
     * @param address
     */
    public void setAddress(String address) {
        this.address = address;
    }

    public String toString() {
        return "Student{name = " + name + ", age = " + age + ", address = " + address + "}";
    }
}

    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //1.获取class字节码文件对象
        Class<?> clazz1 = Class.forName("test6.Student");

        //2.获取构造方法
        Constructor[] cons1 = clazz1.getConstructors();
        for (Constructor con : cons1) {
            System.out.println(con);
        }
        System.out.println("====================");

        Constructor[] cons2 = clazz1.getDeclaredConstructors();
        for (Constructor con : cons2) {
            System.out.println(con);
        }
        System.out.println("===================");

        //获取单个的,getDeclaredConstructor只是能让我们看到这个构造,但是还是无法直接用这个构造去创建对象
        Constructor con3 = clazz1.getDeclaredConstructor();
        System.out.println(con3);

        Constructor con4 = clazz1.getDeclaredConstructor(String.class);
        System.out.println(con4);

        Constructor con5 = clazz1.getDeclaredConstructor(int.class);
        System.out.println(con5);

        Constructor con6 = clazz1.getDeclaredConstructor(String.class,int.class);
        System.out.println(con6);

        int modifiers = con6.getModifiers();
        System.out.println(modifiers);//返回当前方法的权限修饰符个数
        System.out.println("======================");

        Parameter[] parameters = con4.getParameters();//获取该构造方法的参数
        for (Parameter parameter : parameters) {
            System.out.println(parameter);
        }

        //暴力反射:表示临时取消权限校验
        con6.setAccessible(true);
        Object stu = (Student)con6.newInstance("麻瓜", 25);
        System.out.println(stu);
    }

在这里插入图片描述

8. 反射获取成员变量

在这里插入图片描述
Student类:

public class Student {

    private static final long serialVersionUID = 650157805827481085L;
    private String name;
    private int age;
    private String address;


    public Student() {
    }

    public Student(String name, int age, String address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }

    /**
     * 获取
     * @return address
     */
    public String getAddress() {
        return address;
    }

    /**
     * 设置
     * @param address
     */
    public void setAddress(String address) {
        this.address = address;
    }

    public String toString() {
        return "Student{name = " + name + ", age = " + age + ", address = " + address + "}";
    }
}

测试类:

    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        //1.获取class字节码文件的对象
        Class clazz = Class.forName("test6.Student");
        //2.获取所有的成员变量
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        System.out.println("============================");

        //获取单个的成员变量
//        Field address = clazz.getField("address");//获取不到私有的
        Field address = clazz.getDeclaredField("address");//可以获取到私有的
        System.out.println(address);
        System.out.println("==============================");

        //获取权限修饰符
        Field name = clazz.getDeclaredField("name");
        System.out.println(name);

        //获取成员变量的名字
        String n = name.getName();
        System.out.println(n);

        //获取成员变量的数据类型
        Class<?> type = name.getType();
        System.out.println(type);
        System.out.println("===================================");

        //获取成员变量记录的值,这个值和对象有关系
        //所以想要获取值就要先创建一个对象
        Student stu = new Student("里皮",26,"a");
        name.setAccessible(true);//允许私有访问
        Object value = name.get(stu);
        System.out.println(value);

        //修改对象里面记录的值
        name.set(stu,"麻瓜");
        System.out.println(stu);
    }

在这里插入图片描述

9. 反射获取成员方法

在这里插入图片描述

    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        //1.获取class字节码文件的对象
        Class clazz = Class.forName("test6.Student");

        //2.获取里面所有方法对象,包括继承了父类中的所有公共方法
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
        System.out.println("===================================");

        //获取里面所有的方法对象,不能获取父类的,能获取本类中私有的方法
        Method[] methods2 = clazz.getDeclaredMethods();
        for (Method method : methods2) {
            System.out.println(method);
        }
        System.out.println("========================================");

        //获取指定的单一方法
        Method m = clazz.getDeclaredMethod("eat", String.class);//获取指定的方法避免重复
        System.out.println(m);

        //获取方法的修饰符
        int modifiers = m.getModifiers();
        System.out.println(modifiers);

        //获取方法的名字
        String name = m.getName();
        System.out.println(name);

        //获取方法的形参
        Parameter[] parameters = m.getParameters();
        for (Parameter parameter : parameters) {
            System.out.println(parameter);
        }

        //获取方法抛出的异常
        Class<?>[] exceptionTypes = m.getExceptionTypes();
        for (Class<?> exceptionType : exceptionTypes) {
            System.out.println(exceptionType);
        }

        //方法运行
        /*
        Method类中用于创建对象的方法
        object invoke(object obj, object. . . args):运行方法
         */
        Student stu = new Student();
        m.setAccessible(true);
        //参数一:表示方法的调用者
        //参数二:表示在调用方法的时候传递的时间参数
        Object result = m.invoke(stu, "小老板");
        System.out.println(result);//获取返回值

    }

在这里插入图片描述

10. 综合练习

10.1 保存信息

在这里插入图片描述

public class Test {
    public static void main(String[] args) throws IllegalAccessException, IOException {
        Student stu = new Student("麻瓜",26,'男',10.11,"装老师傅");
        Teacher t = new Teacher("小老板",60);

         saveObject(stu);
    }

    // 把对象里面所有的成员变量名和值保存到本地文件当中
    public  static void saveObject(Object obj) throws IllegalAccessException, IOException {
        //1.获取字节码文字的对象
        Class clazz = obj.getClass();

        //IO流
        BufferedWriter bw = new BufferedWriter(new FileWriter("javaprogram1\\b.txt"));

        //2.获取所有的成员变量
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            //获取成员变量的名字
            String name = field.getName();
            //获取成员变量的值
            Object value = field.get(obj);
            bw.write(name+"="+value);
            bw.newLine();

        }
        bw.close();

    }
}

在这里插入图片描述

10.2 跟配置文件结合动态创建

在这里插入图片描述

Techaer类:

public class Teacher {
    private String name;
    private int salary;


    public Teacher() {
    }

    public Teacher(String name, int salary) {
        this.name = name;
        this.salary = salary;
    }

    public void teach(){
        System.out.println("老师在睡觉!");
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return salary
     */
    public int getSalary() {
        return salary;
    }

    /**
     * 设置
     * @param salary
     */
    public void setSalary(int salary) {
        this.salary = salary;
    }

    public String toString() {
        return "Teacher{name = " + name + ", salary = " + salary + "}";
    }
}

配置文件:
在这里插入图片描述
测试类:

public class Test {
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //1.读取配置文件中的信息
        Properties prop = new Properties();
        //把配置文件的信息加载到IO流
        FileInputStream fis = new FileInputStream("javaprogram1\\prop.properties");
        prop.load(fis);//把配置文件的信息读取到了集合当中
        fis.close();
        System.out.println(prop);

        //2.获取全类名
        String classsName = (String) prop.get("classname");
        String  methodName = (String) prop.get("method");
        System.out.println(classsName);
        System.out.println(methodName);

        //3.利用反射创建对象并运行方法
        //获取其字节码文件对象
        Class clazz = Class.forName(classsName);

        //获取构造方法
        Constructor con = clazz.getDeclaredConstructor();
        Object o = con.newInstance();//获取其对象
        System.out.println(o);

        //获取成员方法并运行
        Method method = clazz.getDeclaredMethod(methodName);
        method.setAccessible(true);
        method.invoke(o);
    }
}

在这里插入图片描述
小结:
在这里插入图片描述

动态代理

11. 动态代理的思想分析

假设给下面这个方法去增加其他的功能
在这里插入图片描述
按照以前所学,只能直接修改代码,把其写在该方法当中——侵入式修改

在这里插入图片描述
但是在一个成熟的项目中很少会这么去做,因为一旦修改了可能就会引起连锁反应

这时就需要用到动态代理:
在这里插入图片描述
比如:
在这里插入图片描述
那么这个代理是如何能知道用户要代理唱歌和跳舞的呢?

通过接口来搞定
在这里插入图片描述

代码展示:

star类:
public class star implements mystar{
    private String name;
    public star() {
    }
    @Override
    public String sing(String name){
        System.out.println(this.name+"唱:"+name);
        return "谢谢大家";
    }
    @Override
    public void dance(String name){
        System.out.println(this.name+"正在跳"+name);
    }
    public star(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String toString() {
        return "star{name = " + name + "}";
    }
}

接口:
public interface mystar {
    //把所有想要代理的方法写到接口当中
    public abstract  String sing(String name);
    public abstract void dance(String name);
}

小结:
在这里插入图片描述

12. 动态代理的代码实现

如何为Java对象创建一个代理对象?
在这里插入图片描述
MyStar接口:

public interface MyStar {
    //唱歌
    public abstract String sing(String name);

    //跳舞
    public abstract void dance();
}

BigStar类:

public class BigStar implements MyStar{
    private String name;


    public BigStar() {
    }

    public BigStar(String name) {
        this.name = name;
    }



    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    public String toString() {
        return "BigStar{name = " + name + "}";
    }

    @Override
    public String sing(String name) {
        System.out.println(this.name+"正在唱"+name);
        return "Thanks";
    }

    @Override
    public void dance() {
        System.out.println(this.name+"正在跳舞");
    }
}

代理:

public class ProxyUtil {
    /*
    该方法的作用:
    给一个明星的对象,创建一个代理

    形参:被代理的明星对象

    返回值:给明星创建的代理

    需求:
        外面的人想要大明星唱一首个
        1.获取代理的对象
            代理对象 = ProxyUtil.createProxy(大明星的对象)

         2.再调用代理的唱歌方法
            代理对象.唱歌的方法
     */

    public static MyStar createProxy(BigStar bigStar){
        /*
        参数一:用于指定哪个类加载器,去加载生成的代理类
        参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法
        参数三:用来指定生成的代理对象要干什么事情
         */

        MyStar star = (MyStar) Proxy.newProxyInstance(
                ProxyUtil.class.getClassLoader(),//类加载器加载字节码文件
                new Class[]{MyStar.class},//以数组的方式来体现,中介它可以代MyStart这个接口的所有方法
                new InvocationHandler() {
                    //当没有强转成接口的类时,Proxy.newProxyInstance返回的是Object类型,而用Mystart去接收就肯定会报错
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        /*
                        参数一:代理的对象
                        参数二:
                         */
                        if("sing".equals(method.getName())){
                            System.out.println("准备话筒,收钱");
                        }else if("dance".equals(method.getName())){
                            System.out.println("准备场地,收钱");
                        }
                        //去找大明星开始唱歌或者跳舞
                        //代码的表现形式:调用大明星里面唱歌或者跳舞的方法
                        return method.invoke(bigStar,args);
                    }
                }
        );
        return star;
    }
}

测试类:

public class Test {
    public static void main(String[] args) {
        //1.获取代理的对象
        BigStar bigStar = new BigStar("小黑子");
        MyStar proxy = ProxyUtil.createProxy(bigStar);

        //2.调用唱歌的方法
        String res = proxy.sing("只因");
        System.out.println(res);

        //3.调用跳舞的方法
        proxy.dance();
    }
}

在这里插入图片描述
代码思路:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/22327.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

前端列表页+element-puls实现列表数据弹窗功能

效果图&#xff1a; 这是一个修改的弹窗&#xff0c;我们要实现的功能是&#xff0c;在列表&#xff0c;点击修改按钮时&#xff0c;将数据带入到弹窗里面&#xff0c;点击保存时关闭弹窗。 1&#xff0c;点击修改展开弹窗 使用 eldialog组件&#xff0c;v-model绑定的值为tru…

Godot引擎 4.0 文档 - 入门介绍 - 学习新功能

本文为Google Translate英译中结果&#xff0c;DrGraph在此基础上加了一些校正。英文原版页面&#xff1a; Learning new features — Godot Engine (stable) documentation in English 学习新功能 Godot 是一个功能丰富的游戏引擎。有很多关于它的知识。本页介绍了如何使用…

迪赛智慧数——柱状图(基本柱状图):全球自动化无人机智能支出预测

效果图 全球自动化无人机智能支出及预测分析&#xff0c;2022年机器人流程自动化支出10.4十亿美元&#xff0c;智能流程自动化支出13十亿美元&#xff0c;人工智能业务操作达10.8十亿美元&#xff0c;未来&#xff0c;这些数字将进一步增长&#xff0c;自动化无人机智能也将拥有…

华为OD机试真题 Java 实现【天然蓄水池】【2023Q1 200分】

一、题目描述 公元2919年&#xff0c;人类终于发现了一颗宜居星球——X星。现想在X星一片连绵起伏的山脉间建一个天然蓄水库&#xff0c;如何选取水库边界&#xff0c;使蓄水量最大&#xff1f; 要求&#xff1a; 山脉用正整数数组s表示&#xff0c;每个元素代表山脉的高度。…

Java基础-面向对象总结(3)

本篇文章主要讲解Java面向对象的知识点 面向对象的三大特性类的扩展(抽象类,接口,内部类,枚举) 目录 面向对象和面向过程的区别? 面向对象的五大基本原则 面向对象三大特性 继承 怎么理解继承 ? 继承和聚合的区别&#xff1f; 封装 多态 什么是多态 什么是运行时多…

数字识别问题

文章目录 6.1 MNIST数据处理6.2.1 训练数据6.2.2 变量管理6.3.1 保存模型6.3.1 加载计算图6.3.1 加载模型6.3.2 导出元图 6.1 MNIST数据处理 在直接在第6章的目录下面创建文件 compat.v1.是tensorflow2.x的语法&#xff0c;全部删掉 删除compat.v1.后的代码 # -*- coding: …

基于最新SolVES 模型与多技术融合【QGIS、PostgreSQL、ARCGIS、MAXENT、R】实现生态系统服务功能社会价值评估及拓展案例分析

目录 第一章 理论基础与研究热点 第二章 SolVES 4.0 模型运行环境配置 第三章 SolVES 4.0 模型运行 第四章 数据获取与入库 第五章 环境变量与社会价值的相关分析 第六章 拓展案例分析 SolVES模型&#xff08;Social Values for Ecosystem Services&#xff09;全称为生态…

如何使用SolVES 模型与多技术融合实现生态系统服务功能社会价值评估?

生态系统服务是人类从自然界中获得的直接或间接惠益&#xff0c;可分为供给服务、文化服务、调节服务和支持服务4类&#xff0c;对提升人类福祉具有重大意义&#xff0c;且被视为连接社会与生态系统的桥梁。自从启动千年生态系统评估项目&#xff08;Millennium Ecosystem Asse…

SSL/TLS认证握手过程

一: SSL/TLS介绍 什么是SSL,什么是TLS呢&#xff1f;官话说SSL是安全套接层(secure sockets layer)&#xff0c;TLS是SSL的继任者&#xff0c;叫传输层安全(transport layer security)。说白点&#xff0c;就是在明文的上层和TCP层之间加上一层加密&#xff0c;这样就保证上层信…

Jenkins + docker-compose 在 Centos 上搭建部署

一、前期准备 1. 检查 CentOS上 是否安装 docker 可以使用以下命令&#xff1a; sudo docker version 如果已经安装了Docker&#xff0c;它将显示有关Docker版本和构建信息的输出。如果未安装Docker&#xff0c;将收到有关命令未找到的错误消息。 2. 检查是否安装 docker-…

吴恩达 x OpenAI Prompt Engineering教程中文笔记

Datawhale干货 作者&#xff1a;刘俊君&#xff0c;Datawhale成员 完整课程&#xff1a;《吴恩达ChatGPT最新课程》 &#x1f433;Reasons & Importance Important for research, discoveries, and advancement 对研究、发现和进步很重要 Accelerate the scientific resea…

MySQL 事务篇

事务有哪些特性&#xff1f; 原子性&#xff1a; 一个事务中的所有操作&#xff0c;必须全部执行。要么全部完成要么就不完成。中间如果出现错误&#xff0c;就要回滚到初始状态。 持久性&#xff1a; 事务处理结束后&#xff0c;对数据的修改就是永久的&#xff0c;就是系统故…

Unity UI -- (5)增加基础按钮功能

分析分析一些常见UI 良好的UI设计会清晰地和用户沟通。用户知道他们能和屏幕上哪些东西交互&#xff0c;哪些不能。如果他们进行了交互&#xff0c;他们也要清楚地知道交互是否成功。换句话说&#xff0c;UI要提供给用户很多反馈。 我们可以来看看在Unity里或者在计算机上的任何…

【数据结构】树和二叉树和基本介绍、树的基本术语和表示、二叉树的性质和储存结构

文章目录 1.树的基本概念和介绍1.1树的概念1.2树的基本术语1.3树的使用1.4树的表示1.4.1图形表示1.4.2代码表示 2.二叉树的基本概念和介绍2.1二叉树的介绍2.2二叉树的性质2.3二叉树的储存结构2.3.1顺序储存结构2.3.2链式存储结构 1.树的基本概念和介绍 1.1树的概念 在以前的学…

关于Markdown文件的处理【笔记】

关于Markdown文件的处理【笔记】 前言推荐关于Markdown文件的处理一、md文件转word文档1 准备2 打开3 转为word文档4 导出结果5 打开 二、word文档转md文件1 准备2 导入3 打开4 显示图片5 打开 三、导入到CSDN中1 选择导入2 查看 四、导入设置1 前言2 导入设置3 修改配置 最后 …

C++中map的用法

博主简介&#xff1a;Hello大家好呀&#xff0c;我是陈童学&#xff0c;一个与你一样正在慢慢前行的人。 博主主页&#xff1a;陈童学哦 所属专栏&#xff1a;CSTL 前言&#xff1a;Hello各位小伙伴们好&#xff01;欢迎来到本专栏CSTL的学习&#xff0c;本专栏旨在帮助大家了解…

【分享】ChatGPT的key,用key免费使用ChatGPT(每天更新)

1、ChatGPT用法总结&#xff1a; 自动化文本生成&#xff1a;可以用GPT生成文章、新闻、文本摘要&#xff0c;甚至小说、诗歌等文学作品。语音生成&#xff1a;结合语音合成技术&#xff0c;GPT可以生成自然流畅的语音&#xff0c;可以用于语音助手、交互式语音应用等。问答系统…

深度学习笔记之递归网络(五)递归神经网络的反向传播过程

机器学习笔记之递归网络——递归神经网络的反向传播过程 引言回顾&#xff1a;递归神经网络的前馈计算过程场景构建前馈计算描述 反向传播过程各参数的梯度计算各时刻损失函数梯度计算损失函数对各时刻神经元输出的梯度计算 Softmax \text{Softmax} Softmax回归的梯度计算关于 …

学习git

文章目录 02-为什么要学习Git软件&#xff1f;03 概念&#xff1a;版本控制04 概念&#xff1a;版本控制软件基础功能05 概念&#xff1a;集中式、分布式版本控制系统、多人协作开发5.1 文件冲突问题5.2集中式版本控制&#xff08;CVS&#xff0c;SVN&#xff09;5.3 分布式版本…

【KVM虚拟化】· virsh管理命令

目录 &#x1f341;libvirt架构概述 &#x1f341;使用virsh管理虚拟机 &#x1f342;常用命令总结 &#x1f341;kvm基本功能管理 &#x1f342;帮助命令 &#x1f342;KVM的配置文件存放目录 &#x1f342;查看虚拟机状态 &#x1f342;虚拟机关机与开机 &#x1f342;强制虚…