流程
graph LR
加载-->验证
验证-->准备
准备-->解析
解析-->初始化
初始化-->使用
使用-->卸载
初始化
java虚拟机规范,所有java虚拟机实现必须在每个类或接口被java程序首次主动使用时才初始化。
主动使用的几种情况:
- 创建类的实例
- 访问某个类或者接口的静态变量,或者对该静态变量赋值(如果访问静态编译时常量(即编译时可以确定值的常量)不会导致类的初始化)
- 调用类的静态方法
- 反射(Class.forName(xxx.xxx.xxx))
- 初始化一个类的子类(相当于对父类的主动使用)
- Java虚拟机被标明为启动类的类(包含main方法的)
看下面的实例
package chapter7.classload.initialization;
public class TestClass {
private String name;
public static final int price=10;
static {
System.out.println("Initializing");
}
TestClass() {
System.out.println("Building");
}
TestClass(String name) {
this.setName(name);
}
public static String playToy(String player) {
String msg = player + " plays " ;
System.out.println(msg);
return msg;
}
public void setName(String name) {
this.name = name;
}
}
测试类:
package chapter7.classload.initialization;
public class RunTest1 {
public static void main(String[] args) throws ClassNotFoundException {
// 对上面的类,执行下面的代码:
Class<?> c = Class.forName("chapter7.classload.initialization.TestClass");
// c.newInstance();
}
}
输出:
Initializing
问题
初始化时仅会初始静态代码块(static{}块中)的语句和所有类变量的赋值动作,以下面代码为例,输出结果B的值为2
static class Parent {
public staic int A = 1;
static {
A = 2;
}
}
static class Sub extends Parent {
public static int B = A;
}
public static void main(String[] args) {
System.out.println(Sub.B);
}
分析
Parent是Sub的父类,查看本文开头的规范初始化一个类的子类(相当于对父类的主动使用),所以会初始化Parent类,但初始化时仅会初始化静态代码和类变量赋值,所以,会执行static {
A = 2;
}
, 所以B = 2了
Comments