类初始化学习笔记

类初始化

文章目录

  • 类初始化
    • 一.主动引用:
    • 二.被动引用:
      • 1.子类引用父类的静态变量,不会引起子类的初始化.
      • 2.对常量的引用,不会引起初始化。
      • 3.通过数组定义来引用类,不会触发初始化。
    • 三.针对接口的说明

一.主动引用:

  • 遇到new、getstatic、putstatic或者invokestatic这4条字节指令,如果类没有被初始化过,则会触发类的初始化。也就是说下列情况:
    • new关键字实例化对象
    • 读取或者设置一个类的静态字段(静态常量除外)
    • 调用一个类的静态方法
  • 使用java.lang.reflect包的方法对类进行反射调用的时候。如果类没有被初始化过,则会触发类的初始化。
  • 当初始化一个类的时候,发现其父类还未初始化,则先触发父类的初始化。
  • 虚拟机启动时,先初始化主类。

二.被动引用:

1.子类引用父类的静态变量,不会引起子类的初始化.

对于静态字段,只有直接定义这个字段的类才会进行初始化。

public class SuperClass{
    static{
        System.out.println("SuperClass init...");
    }
    public static int value = 123;
}

public class SubClass extends SuperClass{
    static{
        System.out.println("SubClass init...");
    }
}

public class Test{
    public static void main(String[] args){
        System.out.println(SubClass.value);
    }
}

输出结果为: SuperClass init…

2.对常量的引用,不会引起初始化。

因为常量在编译的时候已经将常量放入调用类的常量池里面。假如A调用B的常量c,经过编译后,常量c已经是A常量池中的常量,Class文件中没有两个类关联的信息,也就是在编译后AB没有任何联系,所以不会引起初始化。

public class ConstClass{
    static{
        System.out.println("ConstClass init...");
    }
    public static final String S = "Const";
}

public class Test{
    public static void main(String[] args){
        System.out.println(ConstClass.S);
    }
}

没有任何输出结果。

3.通过数组定义来引用类,不会触发初始化。

虽然不会初始化我们定义的类,但是会初始化一个由字节码指令newarray触发生成的一个类。

public class ArrayTest{
    static{
        System.out.println("ArrayTest init...");
    }
}

public class Test{
    public static void main(String[] args){
        ArrayTest[] array = new ArrayTest[5];
    }
}

没有任何输出结果。

三.针对接口的说明

主要不同点是,类在初始化的时候要求其父类都初始化过。而接口在初始化的时候并不要求父类接口初始化,只有在真正用到父接口的时候才初始化。

你可能感兴趣的:(study,java,jvm)