基本说明:

反射机制是JAVA实现动态语言的关键,也就是通过反射实现类动态加载。

  1. 静态加载:编译时加载的相关类,如果没有则报错,所以依赖性强。
  2. 动态加载:运行时加载所需要的类,运行时若不用该类则不报错。

类加载有三个阶段五个小步骤:

  1. 加载:JVM将字节码从数据源(class文件、jar包、网络)转换成二进制字节流读入内存,并为之创建一个java.lang.Class对象。此过程由类加载器实现。(JVM自动完成)
  2. 连接:将类的二进制数据合并到JRE中。(JVM自动完成)
  1. 验证:对文件的安全进行校验。包括文件验证(是否以魔数开头)、元数据验证、字节码验证、符号引用验证。
    可以通过设置 Xverify : none 参数来设置关闭验证,缩短类加载的时间。
  2. 准备:对静态变量进行默认初始化(默认设置为值 0)并分配空间。若是static final 的值,因为是不变的常量,所以在这一个阶段JVM会直接赋值到它应该有的值。
  3. 解析:将常量池的符号引用转换成直接引用。简单的说就是把符号转换为相对应的地址引用。
  1. 初始化:在初始化阶段才是真正开始类中定义的JAVA程序代码,是执行<clinit>( )方法的过程,在这个阶段才是程序员可以取控制的地方。
  1. <clinit>( ) 方法:是由编译器按语句在源文件中出现的顺序,依次收集类中所有的静态变量的赋值动作与静态代码块中的语句,并进行合并。
  2. 虚拟机会保证一个类的<clinit>( ) 方法在多线程环境中被正确的加锁、同步。如果多线程同时去初始化一个类,那么只会有一个线程去执行这个 <clinit>( ) 方法,其它的线程则会被阻塞。也正是因为有这个同步机制的存在,所以就算多线程去加载一个类,也不会产生多个CLass对象。

演示类加载的初始化
package practise4_Reflect;
/** 
* 演示类加载的初始化
*/
public class ClassLoad01 {
	public static void main(String[] args) {
		//1. 加载  B类,并生成 B的Class对象
		//2. 连接  num = 0
		//3. 初始化阶段:依次收集类中所有的静态变量的赋值动作与静态代码块中的语句,并进行合并。
		/* clinit(){
		 * 		System.out.println("B 静态代码块被执行");
				// num = 500;
				num = 100;
		 * }
		 * 
		 * clinit发现num = 500会被覆盖,所以num = 500不执行。合并过后,num = 100,
		 */
		new B(); //会自动调用构造器的方法
		System.out.println(B.num);
	}
}

class B{
	static {
		System.out.println("B 静态代码块被执行");
		num = 500;
	}
	static int num = 100;
	
	public B() {
		System.out.println("B 构造器被执行");
	}
}