类的加载
- 类常用的加载机制为:双亲委派 优先委托父类加载,父类加载失败交由子类加载器进行处理。优势:防止重复加载、防止核心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