一、通过子类引用父类的静态字段,不会导致子类初始化
package com.example.jvm;
public class SuperClass {
static {
System.out.println("superClass init!");
}
public static int value = 123;
}
package com.example.jvm;
public class SubClass extends SuperClass {
static {
System.out.print("subclass init!");
}
}
package com.example.jvm;
public class NotInitApp {
public static void main(String[] args) {
System.out.print(SubClass.value);
}
}
输出如下
superClass init!
123
解释说明:对于静态字段,只有直接定义这个字段的类才会被初始化,因此通过其子类来引用父类中定义的静态字段,只会触发父类的初始化而不会触发子类的初始化。
二、通过数组定义来引用类,不会触发此类的初始化
package com.example.jvm;
public class NotInitApp {
public static void main(String[] args) {
SuperClass[] arr = new SuperClass[10];
System.out.println(arr);
}
}
输出入下:
[Lcom.example.jvm.SuperClass;@15db9742
解释说明:运行之后并没有输出"SuperClass init!",说明并没有触发类SuperClass的初始化阶段,但是触发了另外一个名为“[Lcom.example.jvm.SuperClass”类的初始化,对于用户代码而言,这并不是一个合法的类名称,它是一个由虚拟机自动生成的,直接继承于java.lang.Object的子类,创建动作由newarray触发。
三、使用static final修饰的字段被其他类引用的时候不会触发这个类的初始化
package com.example.jvm;
public class ConstantClass {
static {
System.out.println("ConstantClass init!");
}
public static final int value = 10;
}
package com.example.jvm;
public class NotInitApp {
public static void main(String[] args) {
System.out.println(ConstantClass.value);
}
}
输出如下:
10
解释说明:使用static final修饰的常量在编译的时候通过“常量传播优化”已经将对应值写入到NotInitApp常量区了,请看我们使用jd-gui查看对应编译代码已经被修改为10了.
package com.example.jvm;
import java.io.PrintStream;
public class NotInitApp
{
public static void main(String[] args)
{
System.out.println(10);
}
}