如果对Java类的加载机制有了解的话,应该会指定,一个类( class文件)只会在 4种情况下被加载
1. 在虚拟机直接类的字节码时, 遇到 new getstatic putstatic invkesatatic 这4条指令时,如果累还没有进行初始化,那么就会触发初始化,这4条指令的使用场景是:
new 关键字实例化对象, 读取或者设置一个类的静态字段 (这里不包括被static 和final同时修饰的,应该被同时修饰的 视为常量,在编译时期就已经放过常量池了),
以及调用一个类的静态方法
2.初始化一个类时,如果这个类的父类还没有被初始化,那么会先初始化父类
3 虚拟机启动时,所要执行的主类(即程序的入口,main 方法)
4 对某个类进行 反射调用
以上方法称之为类的主动引用,其他的方式呗称为类的被动引用,并不会导致类的加载
举例:
1.通过子类引用父类中的静态字段,这是一个被动引用, 并不会初始化子类,因为只用到了父类的字段
class Father{
public static int m = 33;
static{
System.out.println("父类被初始化");
}
}
class Child extends Father{
static{
System.out.println("子类被初始化");
}
}
public class StaticTest{
public static void main(String[] args){
System.out.println(Child.m);
}
}
程序的输出结果为:
父类被初始化
33
2.常量 常量在编译阶段就会存入调用它的类的常量池中(类的字节码中的常量池) ,本质上没有直接引用到定义该常量的类,因此不会触发定义常量的类的初始化。
class Const{
public static final String NAME = "我是常量";
static{
System.out.println("初始化Const类");
}
}
public class FinalTest{
public static void main(String[] args){
System.out.println(Const.NAME);
}
}
3. 通过数组定义来引用类,不会触发类的初始化
class Const{
static{
System.out.println("初始化Const类");
}
}
public class ArrayTest{
public static void main(String[] args){
Const[] con = new Const[5];
}
}
这里的new 初始化的是一个名为 "LLConst"的类,它是一个有虚拟机自动生成,直接继承与Object 的类,创建动作由字节码指令 newarray触发