欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java类加载的全过程

程序员文章站 2022-07-10 15:24:50
...

类的加载和初始化只有一次

全过程一共分为了七个阶段:

1, 加载                    2,验证 3,准备 4,解析                               5,初始化                         6,使用                  7,卸载

其中 234 蓝色字体又可以认为是 链接的过程  这样看来 我们主要就关注  加载 链接初始化的过程了

******************

加载

将class字节码加载到内存中去,并将这些静态数据 转换成方法区(一种特殊的堆)中数据结构, 同时对应在堆中 生成一个java.lang.class 对象,作为方法区中的数据的入口;   

这个过程需要类加载参与;

链接 

2,验证    确保加载的类的信息符合JVM的规范,没有安全方面的问题

3,准备     正式为类变量分配内存和初始化赋值(比如int的初始值 赋值为0)的操作,这些内存将都在方法去进行分配

4,解析      虚拟机常量池内 的 符号引用 替换为直接引用;

package annotation;

/**
 * 1, 最先初始化静态域
 * 2, 其次 执行构造器
 * 3, 然后打印 a的属性
 *  静态变量(静态域)和静态初始化块被整合成了一块去执行
 * **/

public class TestClassLoad {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		A a= new A();
		System.out.println(a.width);
	}

}
class A{
	static int width;
	{
		System.out.println("初始化静态域");
		width =3000;
	}
	public A() {
		// TODO Auto-generated constructor stub
		System.out.println("构建A");
	}
}

初始化

。初始化是执行类构造器(这个我们直接接触不到)的class intit(clinit)方法的操作,这个方法 是编译器收集了类中的 所有类变量的赋值操作 和 静态语句块的操作合并产生的; 也就是说 除了静态 语句块中的操作会最开始执行;

。虚拟机保证一个类 在各种多线程环境下 线程是安全的 。

 

****************

类的主动引用(会触发初始化)

1,new 一个对象;

2,调用类的静态成员和静态方法(final除外)

3,使用 java.lang.reflect 的方法对类进行发射调用

4,当虚拟机启动 一定会触发,说白了就是main方法所在的类一定会触发加载

5,当初始化一个类,父类没有初始化,那么先初始化父类

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

1,当访问一个类的静态域时,只有真正声明了这个静态域的类才会被初始化(实际上都没有初始化感觉)

package annotation;

/**
 * 当访问一个类的静态域时,只有真正声明了这个静态域的类才会被初始化
 * B作为A的子类, 调用B的继承过来静态属性,不会初始化B,只会初始化属性的实际声明者A
 *  实际上都没有初始化 
 * **/

public class TestClassLoad {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println(B.width);
	}

}
class B extends A{
	static {
		System.out.println("初始化静态域B");
	}
}
class A{
	public static int width=100;
	public static final int max=10;
	{
		System.out.println("初始化静态域A");
	}
	public A() {
		// TODO Auto-generated constructor stub
		System.out.println("构建A");
	}
}

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

package annotation;

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

public class TestClassLoad {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		A [] a=new A[10];
	}

}
class A{
	static int width;
	{
		System.out.println("初始化静态域");
		width =3000;
	}
	public A() {
		// TODO Auto-generated constructor stub
		System.out.println("构建A");
	}
}

3,引用常量 的变量不会引起初始化(在编译阶段 此类就在调用类的常量池中了);同 (调用类的静态成员和静态方法(final))

package annotation;

/**
 * 引用常量 的变量不会引起初始化(在编译阶段 此类就在调用类的常量池中了);同 (调用类的静态成员和静态方法(final)
 * **/

public class TestClassLoad {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println(A.max);
	}

}
class A{
	static int width;
	public static final int max=10;
	{
		System.out.println("初始化静态域");
		width =3000;
	}
	public A() {
		// TODO Auto-generated constructor stub
		System.out.println("构建A");
	}
}