天天看点

JVM类加载、验证、准备、解析、初始化、卸载过程详解(上)0 使用类的准备工作

0 使用类的准备工作

任何程序都需要加载到内存才能与CPU进行交流,同理, 字节码.class文件同样需要加载到内存中,才可以实例化类。

ClassLoader

的使命就是提前加载.class 类文件到内存中,在加载类时,使用的是Parents Delegation Model(溯源委派加载模型)。

Java的类加载器是一个运行时核心基础设施模块,主要是在启动之初进行类的加载、链接、初始化:

  • Java 类加载过程
  • JVM类加载、验证、准备、解析、初始化、卸载过程详解(上)0 使用类的准备工作

Load-加载

由类加载器执行。

读取类文件(通常在 classpath 所指定的路径中查找,但classpath非必须),查找字节码,从而产生二进制流,并转为特定数据结构,初步校验cafe babe魔法数、常量池、文件长度、是否有父类等,然后创建对应类的java.lang.Class实例。

Link-链接

将已读入内存的类的二进制数据合并到 JVM 运行时环境。

包括验证、准备、解析三步:

验证

确保被加载类的正确性。验证类中的字节码,是更详细的校验,比如final是否合规、类型是否正确、静态变量是否合理

准备

为类的static字段分配内存,并设定初始默认值,解析类和方法确保类与类之间的相互引用正确性,完成内存结构布局

解析

如果需要的话,将解析这个类创建的对其他类的所有引用,将常量池的符号引用转换成直接引用 。

Init-初始化

执行类构造器 方法,如果赋值运算是通过其他类的静态方法来完成的,那么会马上解析另外一个类,在虚拟机栈中执行完毕后通过返回值进行赋值

类加载是一个将.class字节码文件实例化成Class对象并进行相关初始化的过程。

在这个过程中,JVM会初始化继承树上还没有被初始化过的所有父类,并且会执行这个链路上所有未执行过的静态代码块、静态变量赋值语句等。

某些类在使用时,也可以按需由类加载器进行加载。

全小写的class是关键字,用来定义类

而首字母大写的Class,它是所有class的类

这句话理解起来有难度,类已经是现实世界中某种事物的抽象,为什么这个抽象还是另外一个类Class的对象?

示例代码如下:

JVM类加载、验证、准备、解析、初始化、卸载过程详解(上)0 使用类的准备工作
JVM类加载、验证、准备、解析、初始化、卸载过程详解(上)0 使用类的准备工作
JVM类加载、验证、准备、解析、初始化、卸载过程详解(上)0 使用类的准备工作
JVM类加载、验证、准备、解析、初始化、卸载过程详解(上)0 使用类的准备工作

 第1处说明:

Class类下的newInstance()在JDK9中已经置为过时,使用getDeclaredConstructor().newInstance()的方式

着重说明一下new与newInstance的区别

new是强类型校验,可以调用任何构造方法,在使用new操作的时候,这个类可以没有被加载过

而Class类下的newInstance是弱类型,只能调用无参构造方法

如果没有默认构造方法,就拋出InstantiationException异常;

如果此构造方法没有权限访问,则拋 IllegalAccessException异常

Java 通过类加载器把类的实现与类的定义进行解耦,所以是实现面向接口编程、依赖倒置的必然选择。

● 第2处说明:

可以使用类似的方式获取其他声明,如注解、方法等

JVM类加载、验证、准备、解析、初始化、卸载过程详解(上)0 使用类的准备工作

 第3处说明: private 成员在类外是否可以修改?

通过

setccessible(true)

,即可使用Class类的set方法修改其值

如果没有这一步,则抛出如下异常:

JVM类加载、验证、准备、解析、初始化、卸载过程详解(上)0 使用类的准备工作

参考

https://javaedge.blog.csdn.net/article/details/105250625