JAVA基础知识六(网络编程、反射)

十、网络编程

计算机网络:

总结:将地理位置不同的计算机设备进行连接,实现数据的共享。

网络编程:

总结:在已有网络的环境下,按照规定实现接收和发送数据即可。

中间过程对于我们不需要关注。

网络模型:

1.网络编程三要素:

1. IP地址:

计算网络中,每个计算机的唯一标识。

IPV4: 由32bit组成,即4个字节,每个字节范围0~255,4个数字组成。

IPV6: 有128bit组成,即16个字节,由8组十六进制数组成

DNS:域名解析器 记忆IP地址不方便,出现了使用名称的表示方式

负责解析名称的,最终转为IP地址形式。

本地回还地址:127.0.0.1 localhost

2. 端口号:

计算中每个应用程序的标识,范围是0~65535 ,其中0~1023被系统占用

3. 协议:

双方通信的规则。

常用:UDP 和 TCP

UDP:

用户数据报包协议

面向无连接,不需要与接收端建立连接,直接发送数据。

不可靠协议,因为数据有可能会丢失,效率高。

如:cts、会议软件、发快递

TCP:

传输控制协议

面向有连接,必须双方建立连接受才能进行数据传输。

可靠协议,不会有数据丢,效率低。

确定连接:

三次握手模式确定连接。

A 发 B 接

第一次,A--->B

第二次:B接到,并给A回信息

第三次:A接到

比如:打电话

InetAddress

在java中是面向对象思想,因此表示计算机唯一标识的这些数字也看成是一类事物,因此就有对应的对象进行描述--InetAddress。

java.net包。

方法:

InetAddress getByName(String host) :根据host获取InetAddress对象

host:可以是主机名或主机的IP地址形式

InetAddress getLocalhost() : 获取本地主机的InetAddress对象

String getHostName(): 获取主机名

String getHostAddress(): 获取主机地址

2.UDP

UDP协议

//创建InetAddress对象
//没有构造方法,只有几个静态方法可以返回这一个InetAddress 类型的对象
    InetAddress inetAddress = InetAddress.getByName("baidu.com");//可以是机器名称,可以是IP地址
    System.out.println(inetAddress);
    String hostName = inetAddress.getHostName();
    System.out.println(hostName);

1.发送

两端:接收端 和 发送端

端点对象: Datagramsocket

包对象: DatagramPacket

发送端:

1.创建Datagramsocket对象

2.创建DatagramPacket对象,并将数据和接收端信息封装到对象中

3.调用send方法发送

4.关闭

        //创建端点对象
        DatagramSocket ds = new DatagramSocket();
        //1.创建包对象
        //2.设置接收端信息,内容信息
        byte[] massage = "你好".getBytes();
        int len = massage.length;
        InetAddress ip = InetAddress.getByName("local");
        int port = 9999;
        //设置四个参数,发送的信息(字节数组类型)、长度、对方的ip、对方的端口号
        DatagramPacket dp = new DatagramPacket(massage,len,ip,port);
        //3.发包
        ds.send(dp);
        System.out.println("数据已发送");
        //4.关闭
        ds.close();

2.接收

接收段:

1.创建Datagramsocket对象,必须指定端口,要与发送端中的包中的端口号要一致

2.创建DatagramPacket对象,用于接受数据

3.调用receive()方法接包

4.拆包

5.关闭

        //1.创建对象并且设置端口号
        DatagramSocket ds = new DatagramSocket(9999);
        //2.准备接收
        //创建数组准备接收
        byte[] by = new byte[1024];
        //获取数组长度
        int len = by.length;
        DatagramPacket dp = new DatagramPacket(by,len);
        //使用这个包获取
        ds.receive(dp);
        byte[] data = dp.getData();
        String s = new String(data,0,dp.getLength());
        System.out.println(s);
        //关闭
        ds.close();

案例实现(网聊):

    //先发后收,设置死循环,特定字符串退出
    public static void main(String[] args) throws IOException {
        Scanner sc = new Scanner(System.in);
        DatagramSocket ds = new DatagramSocket();
        while(true){
            //发
            System.out.print("小明说:");
            String s = sc.next();
            byte[] by = s.getBytes();
            DatagramPacket dp = new DatagramPacket(by,by.length, InetAddress.getLocalHost(),8888);
            ds.send(dp);
            if ("exit".equals(s)){
                System.exit(0);
            }
            //收
            byte[] by1 = new byte[1024];
            DatagramPacket dp1 = new DatagramPacket(by1,1024);
            ds.receive(dp1);
            byte[] data = dp1.getData();
            String s1 = new String(data,0,dp1.getLength());
            System.out.print("小红说:");
            System.out.println(s1);
        }
    }
    //现接收,后发送   
    public static void main(String[] args) throws IOException {
        Scanner sc = new Scanner(System.in);
        DatagramSocket ds = new DatagramSocket(8888);
        while (true){
            //收
            byte[] by = new byte[1024];
            DatagramPacket dp = new DatagramPacket(by,1024);       //创建包
            ds.receive(dp);             //使用这个包接收数据
            byte[] data = dp.getData();     //创建字节数字并使用包获得数据
            String s = new String(data,0,dp.getLength());       //转换为字符串
            if ("exit".equals(s)){
                System.exit(0);
            }
            System.out.print("小明说:"+s);
            System.out.println();
            //发
            System.out.print("小红说:");
            String s1 = sc.next();
            byte[] by1 = s1.getBytes();
            DatagramPacket dp1 = new DatagramPacket(by1,by1.length, dp.getAddress(),dp.getPort());
            ds.send(dp1);
        }
    }

3.广播和组(多)播

UDP协议: 单播 广播 组播

广播:

一个主机可以与该网络内中的所有主机进行数据共享。

广播地址:255.255.255.255

        //广播发送
        public static void main(String[] args) throws IOException {
        //创建对象
        DatagramSocket ds = new DatagramSocket();
        //准备发送
        //创建数组
        byte[] by = "你好".getBytes();
        int len = by.length;
        InetAddress ip = InetAddress.getByName("255.255.255.255");
        int port = 8080;
        DatagramPacket dp = new DatagramPacket(by,len,ip,port);
        ds.send(dp);
        System.out.println("发送完毕");
        ds.close();
        }
        //广播接收
        public static void main(String[] args) throws IOException {
        //创建对象
        DatagramSocket ds = new DatagramSocket(8080);
        //准备接收
        byte[] by = new byte[1024];
        DatagramPacket dp = new DatagramPacket(by,1024);
        ds.receive(dp);
        //拆包
        byte[] data = dp.getData();
        int len = dp.getLength();
        System.out.println("对方发的内容是:"+ new String(data,0,len));
        System.out.println("对方的端口号是"+ dp.getPort());
        System.out.println("对方的地址是:"+ dp.getAddress().getHostName());
        }

4.组播

        //发送
         public static void main(String[] args) throws IOException {
        //创建对象
        MulticastSocket ms = new MulticastSocket();
        //准备发送
        byte[] by = "网络组播".getBytes();
        int len =  by.length;
        InetAddress ip = InetAddress.getByName("224.0.0.23");
        int port = 8080;
        DatagramPacket dp = new DatagramPacket(by,len,ip,port);
        //发送
        ms.send(dp);
        //关闭
        ms.close();
        }
        //接收
    public static void main(String[] args) throws IOException {
        //创建对象
        MulticastSocket ms = new MulticastSocket(8080);
        InetAddress ip = InetAddress.getByName("224.0.0.23");   //小组ip
        //加入组播
        ms.joinGroup(ip);
        while (true){
            //准备接收
            byte[] by = new byte[1024];
            DatagramPacket dp = new DatagramPacket(by,1024);
            ms.receive(dp);
            //显示数据
            byte[] data = dp.getData();
            int len = dp.getLength();
            System.out.println(new String(data,0,len));
            System.out.println("对方的ip是:"+ dp.getAddress().getHostName());
            System.out.println("对方的端口号是:" + dp.getPort());
        }
    }

3.TCP

特点:面向有连接,可靠协议。

两端:客户端和服务端。

客户端:Socket 服务端:ServerSocket

客户端:

1.创建套接字对象,邦定地址,端口号(服务端地址和端口号),socket参数一定要写服务端的ip和端口

2.获取输出流对象,向服务端写数据

3.关闭套接字

1.数据的传输与接送

        //发送
        public static void main(String[] args) throws IOException {
        //客户端发消息
        Socket s = new Socket("localhost",8888);
        //读入写出,获取输出流对象
        OutputStream os = s.getOutputStream();
        os.write("你好".getBytes());
        System.out.println("发送完毕");
        //关闭
        s.close();
        os.close();
        }

服务端:

1.创建服务端端点对象,并邦定端口号(与客户端的端口号要一致)

2.获取Socket对象(侦听要连接的客户端)

3.获取输入流对象,读取客户端数据

4.关闭服务端端点对象

ServerSocket构造方法:

        //接收
        public static void main(String[] args) throws IOException {
        //创建套接字对象
        ServerSocket ss = new ServerSocket(8888);
        //创建侦听器,识别来源信息
        Socket s = ss.accept();
        //读入写出,创建输入流对象
        InputStream is = s.getInputStream();
        //创建数组准备接收
        byte[] by = new byte[1024];
        int len = is.read(by);
        //输出
        String s1 = new String(by,0,len);
        System.out.println(s1);
        System.out.println("对方的ip是"+ s.getInetAddress().getHostName());
        System.out.println("对方的端口号是:"+ s.getPort());
        //关闭
        is.close();
        s.close();
        }

2.文件的传输与接送

    //客户端发文件
    public static void main(String[] args) throws IOException {
        //上传文件---客户端
        Socket s = new Socket("localhost",9090);
        //获取输出流对象
        OutputStream os = s.getOutputStream();
        //定义一个输入流,关联要上传的文件
        FileInputStream fis = new FileInputStream("E:\\0622系统班\\day24\\a.txt");
        byte[] buf = new byte[1024];
        int len ;
        while((len = fis.read(buf)) != -1){
            os.write(buf,0,len);
        }
        //客户端清楚数据都已发送,但是服务端并不知道数据都已接收
        //需要客户端给服务端发送一个结束的标志
        //发送结束标志给服务端
        s.shutdownOutput();
        //关闭流
        fis.close();
        System.out.println("--------文件已发送------------");
        //读取服务单回送的消息
        //获取输入流对象
        InputStream is = s.getInputStream();
        byte[] by = new byte[1024];
        int num = is.read(by);
        System.out.println(new String(by,0,num));
​
        //关闭
        s.close();
    }
        //服务端
        public static void main(String[] args) throws IOException {
        //上传文件---服务端
        ServerSocket ss = new ServerSocket(9900);
        Socket s = ss.accept();
        //定义输出流,用于保存客户端送的文件数据
        //文件重名问题
        String name = UUID.randomUUID().toString().replace("-", "");
        File file = new File("F:\\IdeaProjects\\0622\\day23\\"+name+"txt");
        if (file.exists()){
            name = UUID.randomUUID().toString().replace("-", "");
            file = new File("F:\\IdeaProjects\\0622\\day23\\"+name+"txt");
        }
        //获取输入流对象
        InputStream is = s.getInputStream();
        byte[] buf = new byte[1024];
        int len;
        //read是一个阻塞式方法,客户端并没有发送结束标志,就会一直等待读取数据
        //因此循环不结束
        while((len = is.read(buf)) != -1){
            fos.write(buf,0,len);
        }
        //关闭定义的流
        fos.close();
        System.out.println("-----------------文件已接收-----------------");
        //客户端回送消息
        //获取输出流对象
        OutputStream os = s.getOutputStream();
        os.write("文件已上传成功".getBytes());
​
        //关闭
        s.close();
        ss.close();
    }

3.多线程下的服务端

public class TCPThreadServer {
    public static void main(String[] args) throws IOException {
        //多线程模式下的服务端
        ServerSocket ss = new ServerSocket(8080);
        while(true){
            //侦听连接的客户端
            Socket s = ss.accept();     //侦听一定要放到循环里边,因为发送者是很多人,每个发送者的信息不一样
            Thread  t = new Thread(new MyRun(s));
            t.start();
        }
​
        //ss.close();
    }
}
​
class MyRun implements  Runnable{
    private Socket s;
    public MyRun(Socket s){
        this.s = s;
    }
    @Override
    public void run() {
        try {
            //获取输入流对象
            InputStream is = s.getInputStream();
            byte[] buf = new byte[1024];
            int len = is.read(buf);
            System.out.println("客户端发送的数据是:"+new String(buf,0,len));
            System.out.println("客户端的端口号是:"+s.getPort());
            System.out.println("客户端的地址是:"+s.getInetAddress().getHostAddress());
            System.out.println("------------------------------------------");
            //回送消息
            s.getOutputStream().write("数据已收到".getBytes());
        }catch (IOException e){
            System.out.println(e);
        }finally {
            if(s != null) {
                try {
                    s.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

十一、反射

1.类加载

1.类加载过程

概念: 将class文件从磁盘到内存中,并获取class文件中的数据,对这些数据进行解析,转换等操作,最终成为可使用的java类型,这个过程叫做---类加载过程。

这些过程中: 加载、连接、初始化、使用、卸载

加载:

将class文件从磁盘内存中,为当前这个class文件自动创建一个Class对象。

连接:

验证class文件中内部结构,将一些符号名称转为对应的数据..

初始化:

对类变量进行初始化。

2.什么时候类加载

1.创建该类型对象

2.访问静态成员时

3.获取Class对象时

4.创建子类对象时,父类class文件

5.执行java.exe命令

3.类加载器

概念:类加载器是一个对象,作用就是用来加载class文件的,从磁盘到内存,

并为该class文件,创建一个Class对象。

分类:

Bootstrap ClassLoader :引导类加载器 父

Extension ClassLoader: 扩展类加载器 子

Application ClassLoader:系统类加载器 子子

自定义类加载器,定义类继承ClassLoader。

加载类时,采用的是一种委托机制。

加载类时,会逐级向上委托(App-->ext-->boot,此时不会搜索该类是否存在),boot没有父类,此时boot会查找它的包含范围中是否有该class,如果有就加载,如果没有找ext,ext会查找它的包含范围中是否有该class,如果有就加载,如果没有找app,查找它的包含范围中是否有该class,如果有就加载,如果没有抛出异常,ClassNotFoundException。

Hello.class文件要加载,先逐级委托,委托到boot,搜索boot中是否有hello,如果有就加载,没有去找ext中否是有,有就加载,没有找app,如果有加载,没有抛异常。

2.反射技术

步骤:

\1. 获取Class对象,该Class对象代表这个一个class文件

\2. 获取Class的对象表示的class文件中的内容,并对这些内容进行想要的操作。

反射技术的源头:Class对象。

1.获取Class对象

1.已有对象的情况下: getClass()

Class c1 = p1.getClass();

2.已知类型名的情况下: 类型名.class

Class c2 = Person.class;

3.已知全类名的情况下: Class.forName(“包名.类名”)

Class c3 = Class.forName("Person");

2.构造方法:

1.获取构造方法

  1. getConstructors() 获取所有公共的构造方法,返回一个Constructor数组

Constructor[] cons = c1.getConstructors();

2.getDeclaredConstructors() 获取所有权限的构造方法,返回一个Constructor数组

Constructor[] cons1 = c1.getDeclaredConstructors()

3. getConstructor(String.class,int.class) 已知参数 获取单个公共构造方法

Constructor c1 = c.getConstructor();

4.getDeclaredConstructor(String.class,int.class) 已知参数获取单个构造方法

Constructor c2 = c.getDeclaredConstructor(String.class,int.class)

2.根据构造方法创建实例对象

T newInstance(); 根据指定的构造方法创建对象

基本数据类型也是可以通过 .calss 得到相应的Class类型

1.直接通过Class对象创建实例对象

Person p1 = c1.newInstance();           //前提是这个类有构造方法

2.通过得到的构造方法对象创建实例对象

Constructor con1 = c1.getConstructor();
Person p2 = con1.newInstance();

3.根据有参构造方法创建实例对象,如果方法是private修饰过的属性,需要使用暴力反射

//  c2.setAccessible(true)      参数为true代表取消访问检查,可以操作私有成员
Constructor c2 = c.getDeclaredConstructor(String.class,int.class)
Person p3 = c2.newInstance("小明", 20)

3.File字段

1.获取字段

1. getFields() 获取所有公共属性,包括父类的,返回一个Field数组

Field[]  f1 = c.getFields();

2. getDeclaredFields() 获取所有当前类的属性,返回一个Field数组

Field[]  f2 = c.getDeclaredFields();

3. getField(String name) 获取单个公共属性

Field ff1 = c.getField("b");

4. getDeclaredField(String name) 获取单个属性,忽略权限修饰

Field ff2 = c.getDeclaredField("name");

2.使用字段赋值

  1. field . set(Object obj ,Object value) 给某个实例对象的每个属性赋值

    如果属性是private修饰过的属性,需要使用暴力反射

//创建类对象
Class<Person> c1 = Person.class;
//获取属性
Field namefield = c1.getDeclaredField("name");
//给对象的这个属性赋值
//namefield.setAccessible(true);    暴力反射
Person p = c1.newInstance();
namefield.set(p,"小黑");

4.成员方法

1.获取成员方法

  1. getMethods() 返回所有公共的成员方法,包括继承的,返回一个method数组

    Class c = Class.forName("Person");
    Method[] me1 = c.getMethods();
    1. getDeclaredMethods() 返回本类中的所有成员方法,返回一个method数组

     Method[] me2 = c.getDeclaredMethods();
  2. getMethod("setName", String.class) 已知方法名和参数返回单个公共成员方法

Method m1 = c.getMethod("setName", String.class);
  1. getDeclaredMethod("show") 根据参数返回单个成员方法,忽略权限修饰符

 Method m3 = c.getDeclaredMethod("show");

2.使用方法

  1. Object 方法.invoke(对象,参数) 返回Object类型

m3.invoke(p);
  1. 带返回值的方法

     String  name = (String) m2.invoke(p);
    1. 如果是private修饰过的方法,需要暴力反射

      Method m3 = c.getDeclaredMethod("show");
      m3.setAccessible(true);
      m3.invoke(p);
      ​
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值