JVM类载入过程及主动引用与被动引用

时间:2023-03-09 15:29:32
JVM类载入过程及主动引用与被动引用

了解类载入全过程,有助于了解JVM执行过程,以及更深入了解java动态性(解热部署,动态载入),提高程序灵活性。

类载入全过程:

JVM将class文件字节码文件载入到内存中。并对数据进行校验解析和初始化,终于形成能够直接使用的java类型的过程。

JVM类载入过程及主动引用与被动引用

载入

将class文件字节码内容载入到内存中,并将这些静态数据转换成方法区中的执行时数据结构,在堆中生成一个代表这个类的java.lang.Class对象,作为方法区类数据的訪问入口。

链接

将Java类的二进制代码合并到JVM的执行状态之中的过程。

验证

确保载入的类信息符合JVM规范,没有安全方面的问题。

准备

正式为类变量(static变量)分配内存。并设置类变量初始值的阶段,这些内存都将在方法区中进行分配。

解析

虚拟机常量池内的符号引用替换为直接引用的过程。

初始化

初始化阶段是执行类构造器<clinit>()方法的过程。

类构造器<clinit>()方法是由编译器自己主动收集类中的全部类变量的赋值动作和静态语句块(static块)中的语句合并产生的。

当初始化一个类的时候,假设发现其父类还没有进行过初始化、则须要先触发其父类的初始化。

虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确加锁和同步。

当訪问一个java类的静态域时。仅仅有真正声明这个域的类才会被初始化。

使用

卸载

类载入Demo:

package JVMProcess;
public class Demo {
public static void main(String[] args) {
A a = new A();
System.out.println(A.width);
}
} class A{
public static int width = 100; static{
System.out.println("静态初始化类A");
width = 30;
} public A(){
System.out.println("创建A类的对象");
}
}

执行结果:

静态初始化类A
创建A类的对象
30

JVM类载入过程及主动引用与被动引用

初始化过程Demo

package JVMProcess;

public class DemoInit {
static
{
System.out.println("静态初始化DemoInit");
} public static void main(String[] args) {
System.out.println("DemoInit的main方法");
AInit a = new AInit();
System.out.println(AInit.width);
AInit a2 = new AInit(); //类仅仅会载入和初始化一次,对象能够new多个。
}
} class AInit extends AInit_Father
{
public static int width = 100;//静态变量,静态域 field
static
{
System.out.println("静态初始化类AInit");
width = 30; }
public AInit()
{
System.out.println("创建AInit类的对象");
}
} class AInit_Father{
static{
System.out.println("静态初始化AInit_Father");
}
}

被动引用和主动引用

类的主动引用(一定会发生类的初始化)

new一个类的对象。

调用类的静态成员(除了final常最)和静态方法。

使用java.lang.reflect包的方法对类进行反射调用。

当虚拟机启动,java Hello则一定会初始化Hello类。

说白了就是先启动main方法所在的类。

当初始化一个类,假设其父类没有被初始化,则先会初始化他的父类。

类的被动引用(不会发生类的初始化)

当訪问一个静态域时。仅仅有真正声明这个域的类才会被初始化。

通过子类引用父类的静态变量,不会导致子类初始化。

通过数组定义类引用,用不会触发此类的初始化。

引用常量不会触发此类的初始化(常量在编译阶段就存入调用类的常量池中了)

被动引用和主动引用Demo

package JVMProcess;

public class MPRefDemo {

    public static void main(String[] args) throws ClassNotFoundException {
//主动引用
//new AInitRef();
//System.out.println(AInitRef.width);会初始化AInitRef
//反射调用也会初始化
//Class.forName("JVMProcess.AInitRef"); //被动引用
//常量
//System.out.println(AInitRef.MAX);//不会初始化AInitRef
//数组定义类引用
//AInitRef[] as = new AInitRef[10];
//System.out.println(B.width);//B不会初始化,AInitRef会初始化
System.out.println(B.MAX);//B和AInitRef都不会初始化
}
} class B extends AInitRef
{
static
{
System.out.println("静态初始化类B");
}
} class AInitRef extends AInit_FatherRef
{
public static int width = 100;//静态变量。静态域 field
final static int MAX = 100; static
{
System.out.println("静态初始化类AInit");
width = 30; }
public AInitRef()
{
System.out.println("创建AInit类的对象");
}
} class AInit_FatherRef{
static{
System.out.println("静态初始化AInit_Father");
}
}