Java类什么时候开始初始化

虚拟机规范严格规定了有且只有5种情况必须立即对类进行初始化。
1)遇到new、getstatic、putstatic或invokestatic这4条字节码指令时,如果类没有进行过初始化,则需要先触发其初始化。
2)使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。
3)当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类初始化。
4)当虚拟机启动时,用户需要指定一个要执行的主类(包含main方法的),虚拟机会优先初始化这个主类。
5)当使用JDK1.7的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getStatic等时,这个方法的类还没有进行过初始化,则需要先触发其初始化。
在这里讲几个静态语句的例子,如:
public class ConstClass {
    static {
      System. out .println ( "ConstClass init!!!" );
   }
    public static final String HELLOWORLD = "hello world" ;
    public static final int num = 1;
}
public   class Test {
     public static void main(String[] args) {
           System. out .println( "" + ConstClass. num );
     }
}
 

最后的执行结果为:1,并没有输出ConstClass init!!!。
类Test虽然引用了类ConstClass的常量,但类ConstClass不会因为类Test的引用而初始化,因为类Test已经把类ConstClass中的常量num给引入到自己的常量池中了,所以类Test对类ConstClass常量的引用其实是对类Test自身的常量引用。
类的常量是在类的Class文件中定义的,位于魔数、版本号之后。
如果所ConstClass改为:
public class ConstClass {
    static {
      System. out .println ( "ConstClass init!!!" );
   }
    public static final String HELLOWORLD = "hello world" ;
    public static   int num = 1;
}
最后输出:
ConstClass init!!!
1
所以能看出必须是常量,不能只是静态的。
还有一种情况是子类跟父类的引用关系,如:
public class SuperClass {
    static {
      System. out .println ( "SuperClass init!!!" );
   }
    public static   int num = 123;
}
public class SubClass extends SuperClass{
    static {
      System. out .println ( "SubClass init!!!" );
   }
}
public static void main(String[] args) {
      System. out .println( "" + SubClass. num );
}
这时只输出
SuperClass init!!!
123
这是因为对于静态字段,只有直接定义这个字段的类才会被初始化,因此通过其子类来引用父类中定义的静态字段,只会触发父类的初始化,而不会触发子类的初始化。






你可能感兴趣的:(Java类什么时候开始初始化)