Java类从加载到卸载经历7个阶段:
关键阶段对比:
阶段 | 触发条件 | 主要工作内容 |
---|---|---|
加载 | 首次使用类时 | 读取字节码创建Class对象 |
准备 | 类加载过程中 | 分配内存并设置静态变量默认值 |
初始化 | 首次主动使用类时 | 执行静态代码块和显式初始化 |
public class SingleClass {
// 静态变量声明顺序影响初始化顺序
static String staticField = initStaticField();
static {
System.out.println("静态代码块1");
}
static int staticNum = 5;
static {
System.out.println("静态代码块2");
}
private static String initStaticField() {
System.out.println("静态变量初始化");
return "test";
}
public static void main(String[] args) {
new SingleClass();
}
}
执行结果:
静态变量初始化
静态代码块1
静态代码块2
关键规则:
class Grandparent {
static { System.out.println("Grandparent静态块"); }
{ System.out.println("Grandparent实例块"); }
Grandparent() { System.out.println("Grandparent构造器"); }
}
class Parent extends Grandparent {
static { System.out.println("Parent静态块"); }
{ System.out.println("Parent实例块"); }
Parent() { System.out.println("Parent构造器"); }
}
class Child extends Parent {
static { System.out.println("Child静态块"); }
{ System.out.println("Child实例块"); }
Child() { System.out.println("Child构造器"); }
}
// 测试代码
new Child();
执行结果:
Grandparent静态块
Parent静态块
Child静态块
Grandparent实例块
Grandparent构造器
Parent实例块
Parent构造器
Child实例块
Child构造器
顺序拆解:
new
)final
)Class.forName()
)main()
)class SuperClass {
static int value = 123;
static { System.out.println("SuperClass初始化"); }
}
class SubClass extends SuperClass {
static { System.out.println("SubClass初始化"); }
}
// 测试代码
System.out.println(SubClass.value); // 仅触发SuperClass初始化
输出结果:
SuperClass初始化
123
interface InterfaceA {
int A = Thread.activeCount();
Thread T = new Thread() {
{ System.out.println("InterfaceA初始化"); }
};
}
class InterfaceImpl implements InterfaceA {
static { System.out.println("实现类初始化"); }
}
// 测试代码
System.out.println(InterfaceImpl.A); // 不触发接口初始化
new InterfaceImpl.T(); // 触发接口初始化
执行特点:
开始
↓
父类静态变量/块(按代码顺序)
↓
子类静态变量/块(按代码顺序)
↓
父类实例变量/块(按代码顺序)
↓
父类构造器
↓
子类实例变量/块(按代码顺序)
↓
子类构造器
结束
静父静子先静态,实父构造再实子
class ProblemClass {
static Person p = new Person();
static int length = p.name.length(); // NPE!
}
class Person {
String name;
}
错误原因:
静态变量初始化顺序导致p.name未初始化
解决方案:
调整初始化顺序或保证对象完整初始化
graph TD
Bootstrap[BootStrap ClassLoader] --> Extension[Extension ClassLoader]
Extension --> Application[Application ClassLoader]
Application --> Custom[Custom ClassLoader]
protected Class<?> loadClass(String name, boolean resolve) {
synchronized (getClassLoadingLock(name)) {
// 1. 检查是否已加载
Class<?> c = findLoadedClass(name);
if (c == null) {
// 2. 委派父加载器
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {}
// 3. 自行加载
if (c == null) {
c = findClass(name);
}
}
return c;
}
}
掌握类加载顺序原理,能够帮助开发者:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。