【博学谷学习记录】超强总结,用心分享 。网络编程、日志技术、枚举、类加载器、反射。相关知识。

网络编程、日志技术、枚举、类加载器、反射。

  一、三要素

    1.IP地址:设备在网络中的地址,是唯一的标识(包含ipv4和ipv6,ipv4计算方法是点号计算,ipv6是冒号计算)
    2.端口:应用程序在设备中唯一的标识 一个端口只能被一个应用程序使用
    3.协议:数据在网络中传输的规则,常见的规则有UDP和TCP协议

   二、IP地址

    常用命令

    1、ipconfig:查看本机IP地址

    2、pingIP地址:检查网络是否畅通

        3.特殊IP:127.0.0.1是回送地址也称本地回环地址,可以代表本机的IP地址,一般用来测试使用

  三、网络编程获取主机名和主机ip地址的方法

package com.study.socketDemo;

import java.net.InetAddress;
import java.net.UnknownHostException;

public class InternetDemo {
    public static void main(String[] args) throws UnknownHostException {
        /*
        static InetAddress getByName(String host)
        确定主机名称IP地址,主机名称可以是机器名称,也可以是ip地址
        String getHostName() 获取此IP地址的主机名
        String getHostAddress() 返回文本显示中的ip地址字符串
         */
       InetAddress address=InetAddress.getByName("LAPTOP-2G08AS7E");
       String hostName= address.getHostName();
       String ip= address.getHostAddress();
        System.out.println("主机名为:"+hostName);
        System.out.println("IP地址为:"+ip);
    }
}

    四、两种协议

      1.UDP协议

        用户数据报协议

        UDP是面向无连接通信协议

        速度快,有大小限制一次最多发送64K,数据不安全,易丢失数据

      2.TCP协议

        传输控制协议

        TCP协议是面向连接的通信协议

        速度慢,没有大小限制,数据安全

     五、UDP案例

        发送端

 
package com.study.socketdemo2;

import java.io.IOException;
import java.net.*;
import java.nio.charset.StandardCharsets;

public class ClientDemo {
    public static void main(String[] args) throws IOException {
        //1。找码头
        DatagramSocket ds=new DatagramSocket();

        //2.打包礼物
        //DatagramPacket(byte[] buf,int length, InetAddress address,int port)
        String s="送礼物";
        byte[] bytes=s.getBytes();
        //本机的ip
        InetAddress address=InetAddress.getByName("127.0.0.1");
        //想要发送 的端口
        int port=10000;
        DatagramPacket dp=new DatagramPacket(bytes,bytes.length,address,port);
        //3.发送包裹
        ds.send(dp);
        //4.付钱走人
        ds.close();
    }
}

        接收端

package com.study.socketdemo2;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class ServerDemo {
   
    public static void main(String[] args) throws IOException {
        //接收端
        //1,赵码头   表示接收端从10000端口接收数据的
        DatagramSocket ds=new DatagramSocket(10000);
        //2.创建一个箱子
        byte[] bytes=new byte[1024];
        DatagramPacket dp=new DatagramPacket(bytes, bytes.length);
        //3.接收礼物,把礼物放到新的箱子中
        System.out.println("-----------接收前=------------");
        ds.receive(dp);
        System.out.println("--------------接收后--------------");
        //4.从新的箱子里面获取礼物
        int length=dp.getLength();
        System.out.println(new String(bytes,0,length));
        //5.取完
        ds.close();
    }
}

    注意事项

       1.要先运行接收端,在运行发送端(因为udp是无连接的,如果先运行发送端,没有接收端数据将会丢失)

      2.如果接收端在启动之后,没有接收到数据,那么会死等

      3.在接收数据的时候,需要调用一个getLength方法,表示接收了多少直接

    六、UDP通讯程序

      1.单播:一对一

      2.组播:一对多

      3.广播:一对所有

      组播案例

package com.study.socketDemo4;

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

public class ServiceDemo1 {
    public static void main(String[] args) throws IOException {
        MulticastSocket ms=new MulticastSocket(10000);
        DatagramPacket dp=new DatagramPacket(new byte[1024],1024);
        ms.joinGroup(InetAddress.getByName("224.0.1.0"));
        ms.receive(dp);
        byte[] data = dp.getData();
        int length = dp.getLength();
        System.out.println(new String(data,0,length));
        ms.close();

    }
}

      

package com.study.socketDemo4;

import com.study.socketDemo.InternetDemo;

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

public class ClientDemo {
    public static void main(String[] args) throws IOException {
        DatagramSocket ds=new DatagramSocket();
        String s="hello 组播";
        byte[] bytes=s.getBytes();
        InetAddress address=InetAddress.getByName("224.0.1.0");//组播地址
        int port=10000;
        DatagramPacket dp=new DatagramPacket(bytes, bytes.length,address,port);
        ds.send(dp);
        ds.close();
    }
}

        UDP广播

      

package com.study.socketDemo5;

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

public class ClientDemo {
    public static void main(String[] args) throws IOException {
        DatagramSocket ds=new DatagramSocket();
        String s="hello广播";
        byte[] bytes=s.getBytes();
        InetAddress address=InetAddress.getByName("255.255.255.255");
        int port=10000;
        DatagramPacket dp=new DatagramPacket(bytes, bytes.length,address,port);
        ds.send(dp);
        ds.close();
    }
}

      

package com.study.socketDemo5;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class ServiceDemo {
    public static void main(String[] args) throws IOException {
        DatagramSocket ds=new DatagramSocket(10000);
        DatagramPacket dp=new DatagramPacket(new byte[1024],1024);
        ds.receive(dp);
        byte[] data = dp.getData();
        int length = dp.getLength();
        System.out.println(new String(data,0,length));
        ds.close();
    }
}

    七、TCP服务器与客户端

      1.accept方法是阻塞的,作用就是等待客户端连接

      2.客户端创建对象并连接服务器,此时通过三次握手协议保证跟服务器之前的连接

      3,针对客户端来讲,是往外写的,所以是输出流针对服务器来讲,是往里读的,所以是输入流
      4.read方法也是阻塞的
      5.在关流的时候,还多了一个往服务器写结束标记的动作
      6.最后一部断开连接,通过四次挥手协议保证连接终止

      面试题

        为什么四次挥手会比三次握手多一次?

          因为服务器收到客户端的取消请求,会向服务器确认数据是否要取消,所以才会多一次。

        Ip:是网络中设备的唯一标识

        端口号:设备上应用程序的唯一标识

        协议:计算机网络中,连接和通信的规则被称为网络通信协议

        TCP:传输控制协议,是面向连接的通信协议,每次连接的创建都需要经过“三次握手”,可以保证传输数据的安全,所以应用十分广泛。例如上传文件、下载文件、浏览网页等

        UDP:用户数据报协议,无连接通信协议,使用UDP协议消耗系统资源小,通信效率高,所以通常都会用于音频、视频和普通数据的传输

      案例

    

package com.study.SocketDemo6;

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;

public class ClientDemo {
    public static void main(String[] args) throws IOException {
        //1.创建socket对象,参数为ip地址和端口
        Socket socket=new Socket("127.0.0.1",10000);
        //2.使用IO流输入数据
        OutputStream os=socket.getOutputStream();
        os.write("hello,tcp".getBytes());
        //3,释放资源
        os.close();
        socket.close();
    }
}

    

package com.study.SocketDemo6;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/*
    1.accept方法是阻塞的,作用就是等待客户端连接
    2.客户端创建对象并连接服务器,此时通过三次握手协议保证跟服务器之前的连接
    3,针对客户端来讲,是往外写的,所以是输出流
        针对服务器来讲,是往里读的,所以是输入流
    4.read方法也是阻塞的
 */
public class ServiceDemo {
    public static void main(String[] args) throws IOException {
        //1.创建服务器接收对象
        ServerSocket ss=new ServerSocket(10000);
        //2.创建接收对象
        Socket accept= ss.accept();
        //3.创建输入流
        InputStream is=accept.getInputStream();
        //4.判断输入流是否为空,不为空就输出
        int b;
        while ((b= is.read())!=-1){
            System.out.println((char) b);
        }
        //释放资源
        is.close();
        ss.close();
     socket.close(); } }

      TCP程序文件上传练习

        案例需求

      • 客户端:数据来自于本地文件,接收服务器反馈

        服务器:接收到的数据写入本地文件,给出反馈

      • 案例分析

        •     创建客户端对象,创建输入流对象指向文件,每读一次数据就给服务器输出一次数据,输出结束后使用shutdownOutput()方法告知服务端传输结束

        •     创建服务器对象,创建输出流对象指向文件,每接受一次数据就使用输出流输出到文件中,传输结束后。使用输出流给客户端反馈信息

          •  客户端接受服务端的回馈信息

 
package com.study.socketDemo8;

import java.io.*;
import java.net.Socket;

public class ClientDemo {
    public static void main(String[] args) throws IOException {
        //创建socket对象
        Socket socket=new Socket("127.0.0.1",9999);
        //2.创建本地的流,读取本地文件
        BufferedInputStream bis=new BufferedInputStream(new FileInputStream("D:\\Desktop\\Develop\\Study3" +
                "\\socketmodule\\page\\aa.png"));
        //3.写到服务器--网络中的流 使用socket进行获取
        OutputStream os=socket.getOutputStream();
        //4.使用缓冲流进行输出,提升效率
        BufferedOutputStream bos=new BufferedOutputStream(os);
        //5.进行判断输出
        int b;
        while ((b= bis.read())!=-1){
            bos.write(b);//如果本地文件不为空,就通过网路写到服务器中去
        }
        bos.flush();
        //给服务器一个标记,告诉服务器文件已经传输完毕
        socket.shutdownOutput();

        //接收服务器的反馈信息
        BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String line;
        while ((line= br.readLine())!=null){
            System.out.println(line);
        }
        bis.close();
        socket.close();

    }
}
package com.study.socketDemo8;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/*
     客户端:数据来自于本地文件,接收服务器反馈
      服务器:接收到的数据写入本地文件,给出反馈
- 案例分析
  - 创建客户端对象,创建输入流对象指向文件,每读一次数据就给服务器输出一次数据,输出结束后使用shutdownOutput()方法告知服务端传输结束
  - 创建服务器对象,创建输出流对象指向文件,每接受一次数据就使用输出流输出到文件中,传输结束后。使用输出流给客户端反馈信息
  - 客户端接受服务端的回馈信息
 */
public class ServiceDemo {
    public static void main(String[] args) throws IOException {
        ServerSocket ss=new ServerSocket(9999);
        Socket accept = ss.accept();
        //使用网络中的流读取客户端传递过来的数据 对于服务器来说是输入
        BufferedInputStream bis=new BufferedInputStream(accept.getInputStream());
        //把本地的io流数据写到本地中,实现永久化存储
        BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("D:\\Desktop\\Develop\\Study3\\socketmodule\\page\\copy.png"));
        //进行判断输出
        int b;
        while ((b=bis.read())!=-1){
            bos.write(b);
        }

        //给客户端进行反馈,提示是否上传成功
        BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
        bw.write("上传成功");
        bw.newLine();
        bw.flush();
        bos.close();
        accept.close();
        ss.close();




    }
}

    总结:获取本地文件就是通过本地的io流在客户端使用bis获取,然后写到网络中的流去BOS,然后传递到服务端,在服务端先要获取网络中的流,写到服务器中也是 bis,然后获取的数据写到本地中实现存储使用bos,最后在来反馈

      服务器优化

        弊端:第二次上传文件的时候,会把第一次的文件给覆盖

        改进方法:UUID.randomUUID() 方法生成随机的文件名

package com.study.socketDemo8;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.UUID;

/*
     客户端:数据来自于本地文件,接收服务器反馈
      服务器:接收到的数据写入本地文件,给出反馈
- 案例分析
  - 创建客户端对象,创建输入流对象指向文件,每读一次数据就给服务器输出一次数据,输出结束后使用shutdownOutput()方法告知服务端传输结束
  - 创建服务器对象,创建输出流对象指向文件,每接受一次数据就使用输出流输出到文件中,传输结束后。使用输出流给客户端反馈信息
  - 客户端接受服务端的回馈信息
 */
public class ServiceDemo {
    public static void main(String[] args) throws IOException {
       ServerSocket ss=new ServerSocket(10000);
       //加上while循环进行服务器优化,能使多个客户端获取
        while (true) {
            Socket accept = ss.accept();
            //获取网络流
            BufferedInputStream bis=new BufferedInputStream(accept.getInputStream());
            //本地的io流把数据写到本地中,实现永久化存储
            BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("D:\\Desktop\\Develop\\Study3" +
                    "\\socketmodule\\page\\ "+ UUID.randomUUID().toString()+".png"));
            int b;
            while ((b= bis.read())!=-1){
                bos.write(b);
            }

            BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
            bw.write("上传成功");
            bw.newLine();
            bw.flush();
            bos.close();
            accept.close();
        }
//        ss.close();
    }
}

      服务器优化二、

        加入循环后引发了一个问题L使用循环虽然可以让服务器处理多个客户端请求,但是还是无法同时跟多个客户端通信

        改进方法:开启多线程处理

      

package com.study.socketDemo9;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.UUID;

/*
     客户端:数据来自于本地文件,接收服务器反馈
      服务器:接收到的数据写入本地文件,给出反馈
- 案例分析
  - 创建客户端对象,创建输入流对象指向文件,每读一次数据就给服务器输出一次数据,输出结束后使用shutdownOutput()方法告知服务端传输结束
  - 创建服务器对象,创建输出流对象指向文件,每接受一次数据就使用输出流输出到文件中,传输结束后。使用输出流给客户端反馈信息
  - 客户端接受服务端的回馈信息
 */
public class ServiceDemo {
    public static void main(String[] args) throws IOException {
       ServerSocket ss=new ServerSocket(10000);
       //加上while循环进行服务器优化,能使多个客户端获取
        while (true) {
            Socket accept = ss.accept();
            ThreadSocketDemo ts=new ThreadSocketDemo(accept);
            new Thread(ts).start();
//        ss.close();

        }

    }
}

    

package com.study.socketDemo9;

import java.io.*;
import java.net.Socket;
import java.util.UUID;

public class ThreadSocketDemo implements Runnable{
    private Socket acceptSocket;
    public ThreadSocketDemo(Socket accept) {
        this.acceptSocket=accept;
    }

    @Override
    public void run() {
        BufferedOutputStream bos=null;
        try {
            //获取网络流
            BufferedInputStream bis=new BufferedInputStream(acceptSocket.getInputStream());
            //本地的io流把数据写到本地中,实现永久化存储
             bos=new BufferedOutputStream(new FileOutputStream("D:\\Desktop\\Develop\\Study3" +
                    "\\socketmodule\\page\\ "+ UUID.randomUUID().toString()+".png"));
            int b;
            while ((b= bis.read())!=-1){
                bos.write(b);
            }

            BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(acceptSocket.getOutputStream()));
            bw.write("上传成功");
            bw.newLine();
            bw.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bos!=null){
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
           if (acceptSocket !=null){
               try {
                   acceptSocket.close();
               } catch (IOException e) {
                   e.printStackTrace();
               }
           }

        }
    }
}

      服务器优化

        加入多线程以后又引发了一个问题:使用多线程虽然可以让服务器同时处理多个客户端请求。但是资源消耗太大

        改进方式:加入线程池

      

package com.study.socketThreadDemo;

import com.study.socketDemo9.ThreadSocketDemo;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/*
     客户端:数据来自于本地文件,接收服务器反馈
      服务器:接收到的数据写入本地文件,给出反馈
- 案例分析
  - 创建客户端对象,创建输入流对象指向文件,每读一次数据就给服务器输出一次数据,输出结束后使用shutdownOutput()方法告知服务端传输结束
  - 创建服务器对象,创建输出流对象指向文件,每接受一次数据就使用输出流输出到文件中,传输结束后。使用输出流给客户端反馈信息
  - 客户端接受服务端的回馈信息
 */
public class ServiceDemo {
    public static void main(String[] args) throws IOException {
       ServerSocket ss=new ServerSocket(10000);
       //使用线程池减少服务器资源消耗
        ThreadPoolExecutor pool=new ThreadPoolExecutor(
                3,//核心线程数量
                10,//线程池的总数量
                60,//临时线程空闲时间
                TimeUnit.SECONDS,//临时线程空闲时间单位
                new ArrayBlockingQueue<>(5),//阻塞队列
                Executors.defaultThreadFactory(),//创建线程的默认方式
                new ThreadPoolExecutor.AbortPolicy()//拒绝策略
        );
       //加上while循环进行服务器优化,能使多个客户端获取
        while (true) {
            Socket accept = ss.accept();
            ThreadSocketDemo ts=new ThreadSocketDemo(accept);
//            new Thread(ts).start();
            //线程池
            pool.submit(ts);
//        ss.close();

        }

    }
}

    八、日志技术

      特点:

      1.通过使用日志技术,我们可以控制日志信息输送的目的地是控制台、文件等位置

      2.我们也可以控制每一条日志的输出格式

      3.通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程

      4.最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用代码

      基本使用

        

package com.study.logdemo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Scanner;

public class LogDemo {
    //获取logger对象
    private static final Logger LOGGER=LoggerFactory.getLogger(Logger.class);

    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        System.out.println("请输入您的姓名:");
        String name= sc.nextLine();
        LOGGER.info("用户输入姓名为"+name);
        System.out.println("请输入您的年龄:");
        String age= sc.nextLine();
        try {
            int ageInt = Integer.parseInt(age);
            LOGGER.info("用户输入的年龄格式正确"+age);
        }catch (NumberFormatException e){
            LOGGER.info("用户输入的年龄格式错误:"+age);
        }
    }

}

      日志技术

        1.如果系统上线后只想记录一些错误信息或者不想记录日志了怎么办?
        可以通过设置日志的输出级别来控制哪些日志信息输出或者不输出

      日志的六种级别

        级别程度依次是:TRACE<DEBUG<INFO<WARN<ERROR<FATAL

        默认级别是debug

        作用:将开发中不同的日志信息进行分类,只输出大于等于该级别的日志信息

        ALL和OFF分别是打开全部日志信息,及关闭全部日志信息

   九、枚举     

      为了间接的表示一些固定的值,java就给我们提供了枚举

      枚举的特点

         1.所有枚举类都是Enum的子类

         2.我们可以通过“枚举类名.枚举项名称”去访问指定的枚举项

         3.每一个枚举项其实就是该枚举的一个对象

         4.枚举也是一个类,也可以去定义成员变量

           5.枚举类的第一行上必须是枚举项,最后一个枚举项后的分号是可以省略的,但是如果枚举类有其他的 东西,这个分号就不能省略。建议不要省略

         6.枚举类可以有构造器,但是必须是private的,他默认的也是private

          7.枚举类也可以有抽象方法,但是枚举项必须重写该方法

      枚举的方法

package com.study.EnumDemo2;

public class EnumDemo2 {
    public static void main(String[] args) {
        /*

  | -----------------------------------
  | String name()   | 获取枚举项的名称
  | int ordinal()     | 返回枚举项在枚举类中的索引值
  | int compareTo(E  o)   | 比较两个枚举项,返回的是索引值的差值 |
  | String toString()    | 返回枚举常量的名称
  | static <T> T  valueOf(Class<T> type,String  name) | 获取指定枚举类中的指定名称的枚举值   |
  | values()       | 获得所有的枚举项
         */
        //String name()   | 获取枚举项的名称
        String name=Season.SPRING.name();
        System.out.println(name);
        //| int ordinal() | 返回枚举项在枚举类中的索引值
        int index1=Season.SPRING.ordinal();
        int index2=Season.SUMMER.ordinal();
        int index3=Season.AUTUMN.ordinal();
        int index4=Season.WINTER.ordinal();
        System.out.println(index1);
        System.out.println(index2);
        System.out.println(index3);
        System.out.println(index4);
//        | int compareTo(E  o)   | 比较两个枚举项,返回的是索引值的差值 |
        int result = Season.SPRING.compareTo(Season.WINTER);
        System.out.println(result);
//         | String toString()    | 返回枚举常量的名称
        String s = Season.SPRING.toString();
        System.out.println(s);
//        | static <T> T  valueOf(Class<T> type,String  name) | 获取指定枚举类中的指定名称的枚举值
        Season spring = Enum.valueOf(Season.class, "SPRING");
        System.out.println(spring);
        System.out.println(Season.SPRING == spring);
//          | values()       | 获得所有的枚举项
        Season[] values = Season.values();
        for (Season value : values) {
            System.out.println(value);
        }
    }
}

      十、类加载器

         作用:负责将.class文件(存储的物理文件)加载在到内存中

         类加载时机

          1.创建类的实例(对象)

          2.调用类的类方法

          3.访问类或者接口的类变量,或者为该类变量赋值

          4.使用反射方式来强制创建某个类或接口对应的java.lang.Class对象

          5.初始化某个类的子类

          6.直接使用java.exe命令来运行某个主类

         类加载器的分类

          启动类加载器(Bootstrap ClassLoader):虚拟机内置的类加载器

          平台类加载器(Platform ClassLoader):负责加载JDK中一些特殊的模块

          系统类加载器(System ClassLoader): 负责加载用户类路径上所指定的类库

package com.study.classLoaderDemo;

public class ClassLoaderDemo1 {
    public static final ClassLoader SYSTEM_CLASS_LOADER = ClassLoader.getSystemClassLoader();

    public static void main(String[] args) {
        //双亲委派模型
        //获得系统类加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        //获得平台类加载器
        ClassLoader parent1 = systemClassLoader.getParent();
        //获得启动类加载器
        ClassLoader parent2 = parent1.getParent();
        System.out.println("系统类加载器"+systemClassLoader);
        System.out.println("平台类加载器"+parent1);
        System.out.println("启动类加载器"+parent2);


    }
}

        类加载器的两个方法

          

package com.study.classLoaderDemo;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class ClassLoaderDemo2 {
    public static void main(String[] args) throws IOException {
        //加载某一个资源文件
        //InputStream getResourceAsStream(String name)
        //获取系统类加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        //利用加载器去加载一个指定文件
        //参数文件的路径
        //返回值:字节流
        //输入流获取文件中的资源
        InputStream is=systemClassLoader.getResourceAsStream("prop.properties");
        //创建对象
        Properties prop=new Properties();
        //获取对象的数据
        prop.load(is);
        System.out.println(prop);
        is.close();
    }
}

        类加载的过程:加载、验证、准备、解析、初始化

          加载:通过包名+类名,获取这个类,准备用流进行传输,在这个类加载到内存中,加载完毕后创建一个class对象(用来存储类中的内存中的信息)

          验证:衔接阶段的第一步,这一阶段为了确保class文件字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身安全,也就是查看文件中的信息是否符合虚拟机规范并且有没有安全隐患

          准备:负责为类的类变量(被static修饰的变量)分配内存,并设置默认初始化值。

          解析:将类的二进制数据流中的符号引用替换为直接引用,即本类中如果用到 了其他类,此时就需要找到对应的类。

          初始化:根据程序员通过程序制定的主观计划去初始化类变量和其他资源。

          小结:

            当一个类被使用的时候,才会加载到内存

            类加载的过程包括:加载、验证、准备、解析、初始化

    十一、反射

        java反射机制

          是在运行状态中,对于任意一个类,都能够知道这个类的所有属性方法;

          对于任意一个对象,都能调用它的任意方法和属性

          这种动态获取信息以及动态调用对象方法的功能称之为java语言的反射机制

          也就是利用反射可以无视修饰符获取类里面所有的属性和方法。先获取配置文件中的信息,动态获取信息并创建对象和调用方法

          用反射创建对象、反射调用成员变量、反射调用成员方法、利用反射调用他类中的属性和方法时,无视修饰符(private、public)

        反射获取Class类的对象

            Class.forName("全类名")
            类名.class
            对象.getClass();
public class ReflectDemo1 {
    public static void main(String[] args) throws ClassNotFoundException {
        /*
        .Class类中获取对象的三种方法
         */
        //1.Class类中的静态方法forName("全类名")
        Class  aClass = Class.forName("com.study.myreflect.Student");
        System.out.println(aClass);

        //2.通过class属性来获取
        Class aClass1=Student.class;
        System.out.println(aClass1);

        //3.利用对象的getClass方法来获取class对象
        //getClass方法是定义在object类中
        Student s=new Student();
        Class aClass2 = s.getClass();
        System.out.println(aClass2);
    }
}

      Class类获取构造方法对象的方法

      

          方法介绍

方法名说明
Constructor<?>[] getConstructors() 返回所有公共构造方法对象的数组
Constructor<?>[] getDeclaredConstructors() 返回所有构造方法对象的数组
Constructor<T> getConstructor(Class<?>... parameterTypes) 返回单个公共构造方法对象
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)

      

      获取Constructor对象并获取对象

      | T newInstance(Object...initargs) | 根据指定的构造方法创建对象 |

       | setAccessible(boolean flag) | 设置为true,表示取消访问检查 |

posted @ 2022-10-16 21:14  LINwenguan  阅读(24)  评论(0编辑  收藏  举报