Java SE -类的加载过程

1、加载

<1、获取.class文件的二进制流

<2、将类信息、静态变量、字节码、常量这些.class文件中的内容放入方法区中

<3、在内存中生成一个代表这个.class文件的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。

(1)预加载:虚拟机启动时加载,加载的是JAVA_HOME/lib/下的rt.jar下的.class文件,这个jar包里面的内容是程序运行时非常常常用到的,像java.lang.*、java.util.*、java.io.*等等;

(2)运行时加载:虚拟机在用到一个.class文件的时候,会先去内存中查看一下这个.class文件有没有被加载,如果没有就会按照类的全限定名来加载这个类。

2、连接  (验证----准备----解析)

<1  验证

文件格式验证

.class文件的第5~第8个字节表示的是该.class文件的主次版本号,验证的时候会对这4个字节做一个验证,高版本的JDK能向下兼容以前版本的.class文件,但不能运行以后的class文件,即使文件格式未发生任何变化,虚拟机也必须拒绝执行超过其版本号的.class文件。举个具体的例子,如果一段.java代码是在JDK1.7下编译的,7JDK1.7的环境能运行这个.java代码生成的.class文件,但是JDK1.57及更低的JDK版本是无法运行这个.java代码生成的.class文件的。如果运行,会抛出java.lang.UnsupportedClassVersionError。

元数据验证

字节码验证

符号引用验证

<2 准备

这时候进行内存分配的static修饰的类变量,而不是实例变量,实例变量将会在对象实例化的时候随着对象一起分配在Java堆中,这个阶段赋初始值的变量指的是那些不被final修饰的static变量;

public static int val= 1;value在准备阶段过后是0而不是1,给value赋值为1的动作将在初始化阶段才进行;

public static final int val= 1;在准备阶段,虚拟机就会给value赋值为1;

<3  解析

解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程

符号引用包括了下面三类常量:类和接口的全限定名、字段的名称和描述符、方法的名称和描述符

直接引用可以是直接指向目标的指针、相对偏移量或是一个能间接定位到目标的句柄

3、初始化

初始化阶段做的事就是给static变量赋予用户指定的值(final修饰除外)以及执行静态代码块

该阶段会执行类的构造器clinit()方法,并且会用锁保证多线程情况下,只有一个类执行

Java虚拟机规范对一个类进行主动引用场景..

1、使用new关键字实例化对象、读取或者设置一个类的静态字段(被final修饰的静态字段除外)、调用一个类的静态方法的时候

2、使用java.lang.reflect包中的方法对类进行反射调用的时候

3、初始化一个类,发现其父类还没有初始化过的时候

4、虚拟机启动的时候,虚拟机会先初始化用户指定的包含main()方法的那个类

猜你喜欢

转载自blog.csdn.net/Hao_0802/article/details/81301349