Class 加载机制


类的加载

  • 类常用的加载机制为:双亲委派 优先委托父类加载,父类加载失败交由子类加载器进行处理。优势:防止重复加载、防止核心API库被篡改。
  • JVM加载类整个生命周期包括:加载(Loading)、验证(Verification)、准备(Preparation)、解析 (Resolution)、初始化(Initialization)、使用(Using)和卸载(Unloading)。

三大加载器

  • 启动类加载器(BootStrap ClassLoader),主要用于加载JVM自身需要的类,将我们配置的JAVA_HOME/lib路径下的核心jar包加载到内存中,如 rt.jar包。
  • 扩展类加载器(Extension ClassLoader),将JAVA_HOME/lib/ext目录下的类库加载到内存中。
  • 系统类加载器(System ClassLoader),由AppClassLoader实现。负责将java -classpath所指定目录下的class加载到内存中,开发过程中我们使用的该加载器。

类的初始化顺序

基类的静态代码块 –> 迭代类的静态代码块 –> 基类的构造代码块 –> 基类的构造函数 –> 迭代类的构造块 –> 迭代类的构造函数

class B {
	// static顺序执行!!!!
    public static B b = new B();
    {
        System.out.print("基类构造块 ");
    }

    static {
        System.out.print("基类静态块 ");
    }

    public B() {
        System.out.print("基类构造函数 ");
    }
}
public class A extends B {
	// static 
    public static A a = new A();
	
    {
        System.out.print("A构造块 ");
    }
    static {
        System.out.print("A静态块 ");
    }
    public static void main(String[] args) {
        new A();
    }
}

output:

基类构造块 基类构造函数 基类静态块 基类构造块 基类构造函数 A构造块 A静态块 基类构造块 基类构造函数 A构造块

package com.dkd.typeinfo.toys;

import java.util.Random;

/**
 * 类的初始化步骤:
 *   1.类加载器进行加载
 *   2.链接,验证类的字节码
 *   3.初始化,存在惰性初始化
 * @author Deng_kdi
 *
 */

class Initable {
	static final int staticFinal = 47;
	static final int staticFinal2 =
			ClassInitialization.rand.nextInt(1000);
	// 验证初始化了没有
	static {
		System.out.println("Initializing Initable");
	}
}

class Initable2 {
	static int staticNonFinal = 147;
	static {
		System.out.println("Initializing Initable2");
	}
}

class Initable3 {
	static int staticNonFinal = 74;
	static {
		System.out.println("Initializing Initable3");
	}
}

public class ClassInitialization {

	public static Random rand = new Random(47);
	
	public static void main(String[] args) throws Exception{
		
		
		/**此时并不会初始化Initable类,若初始化的话
		 * 将在下面的After输出语句之前打印
		 * Initable类里面定义的输出语句
		 * 所以它进行的是延迟初始化,
		 * 在Initable.staticFinal的时候才对类进行初始化
		 **/
		Class initable = Initable.class; 
		System.out.println("After creating Initable ref");
		
		System.out.println(Initable.staticFinal);
		System.out.println(Initable.staticFinal2);
		
		// Class initable2 = Initable2.class;
		System.out.println("==Initable2==");
		System.out.println(Initable2.staticNonFinal);
		
		/**
		 * Class.forName()的时候会立即对类进行初始化,
		 * 所以当打印Initable3.staticNonFinal的时候
		 * 类已经初始化完成。
		 */
		System.out.println("==Initable3===");
		Class initable3 = Class.forName("com.dkd.typeinfo.toys.Initable3");
		System.out.println("After creating initable3 ref");
		System.out.println(Initable3.staticNonFinal);
	}
}

output:

After creating Initable ref
47
Initializing Initable
258
==Initable2==
Initializing Initable2
147
==Initable3===
Initializing Initable3
After creating initable3 ref
74