类加载时机
什么情况下虚拟机需要开始加载一个类呢?虚拟机规范中并没有对此进行强制约束,这点可以交给虚拟机的具体实现来自由把握。
类初始化时机
1)遇到new、getstatic、putstatic或invokestatic这四条字节码指令(注意,newarray指令触发的只是数组类型本身的初始化,而不会导致其相关类型的初始化,比如,new String[]只会直接触发String[]类的初始化,也就是触发对类[Ljava.lang.String的初始化,而直接不会触发String类的初始化)时,如果类没有进行过初始化,则需要先对其进行初始化。生成这四条指令的最常见的Java代码场景是:
-
使用new关键字实例化对象的时候;
-
读取或设置一个类的静态字段(被final修饰,已在编译器把结果放入常量池的静态字段除外)的时候;
-
调用一个类的静态方法的时候。
-
使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。
-
当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。
-
当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个主类。
-
当使用jdk1.7动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getstatic,REF_putstatic,REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行初始化,则需要先出触发其初始化
[](
)被动引用的几种经典场景
==============================================================================
通过子类引用父类的静态字段,不会导致子类初始化
public class SSClass {
static {
【一线大厂Java面试题解析+核心总结学习笔记+最新架构讲解视频+实战项目源码讲义】 浏览器打开:qq.cn.hn/FTf 免费领取
System.out.println( “SSClass” );
}
}
public class SClass extends SSClass {
static {
System.out.println( “SClass init!” );
}
public static int value = 123;
public SClass()
{
System.out.println( “init SClass” );
}
}
public class SubClass extends SClass {
static {
System.out.println( “SubClass init” );
}
static int a;
public SubClass()
{
System.out.println( “init SubClass” );
}
}
public class NotInitialization {
public static void main( String[] args )
{
System.out.println( SubClass.value );
}
}
通过数组定义来引用类,不会触发此类的初始化
public class NotInitialization{
public static void main(String[] args){
SClass[] sca = new SClass[10];
}
}
常量在编译阶段会存入调用类的常量池中,本质上并没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化
public class ConstClass{
static{
System.out.println(“ConstClass init!”);
}
public static final String ConSTANT = “hello world”;
}
public class NotInitialization{
public static void main(String[] args){
static{
System.out.println(“ConstClass init!”);
}
public static final String ConSTANT = “hello world”;
}
public class NotInitialization{
public static void main(String[] args){



