类初始化

来源:互联网 发布:电脑报 淘宝二手苹果 编辑:程序博客网 时间:2024/05/22 06:13
加载阶段,java虚拟机规范中并没有进行强制约束;

但初始化阶段,虚拟机规范则严格规定了有且只有5种情况必须立即对类进行“初始化”;

1)遇到new,getstatic,putstatic 或invokestatic指令,如果类没有进行过初始化,则需要先触发初始化;
即使用new 实例化对象,读取或设置一个类的静态变量(被final修饰,已在编译期把结果放入常量池的静态字段除外)的时候,以及调用一个类的静态方法的时候。

2)使用java.lang.reflect 包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化;

3)当初始化一个类的时候,如果发现父类还没有进行过初始化,则需要先触发其父类的初始化。

4)当虚拟机启动时,用户需要指定一个要执行的主类(包括 main()方法的那个类),虚拟机会先初始化这个类;

5)当使用JDK1.7 的动态语言支持时,如果一个java.lang.invoke.MethodHandle 实例最后的解析结果REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且这个句柄所对应的类没有进行初始化,则需要先触发其初始化。

举几个例子说明:
public class Parent {    public static String PARENT ="parent";    public static final String FINAL_PARENT = "final_parent";    static {        System.out.println("parent static code");    }    public Parent(){        System.out.println("parent init");    }    public static String getStatic(){        return "parent static method";    }}


public class Sub extends Parent {    public static String PARENT ="sub";    static {        System.out.println("sub static code");    }    public Sub(){        System.out.println("sub init");    }//    public static String getStatic(){//        return "sub static method";//    }}


例子1: 没有new,不会初始化Parent 类

public class Main {    public static void main(String[] args){        Parent parent;    }}

结果:没有任何输出

查看Main.class,可以看出Main这个类没有Parent类的入口,说明编译的时候就会遵守虚拟机的一些规则

public class Main {
    public Main() {
    }

    public static void main(String[] args) {
    }
}

例子2: new 会引发类初始化

public class Main {

    public static void main(String[] args){
        Parent parent = new Parent();
    }
}

结果:输出:
parent static code
parent init

查看Main.clas,有了new Parent入口
public class Main {
    public Main() {
    }

    public static void main(String[] args) {
        new Parent();
    }
}


例子3: 获取static变量,会类初始化,不会调用构造函数

public class Main {

    public static void main(String[] args){
        System.out.println(Parent.PARENT);
    }
}

输出:
parent static code
parent


对应class类
public class Main {
    public Main() {
    }

    public static void main(String[] args) {
        System.out.println(Parent.PARENT);
    }
}

例子4:设置static变量,会类初始化,不会调用构造函数

public class Main {

    public static void main(String[] args){
        Parent.PARENT = "hello";
    }
}

输出:
parent static code

例子5: 调用被final修饰,已在编译期把结果放入常量池的静态字段,不会类初始化

public class Main {

    public static void main(String[] args) {
        System.out.println(Parent.FINAL_PARENT);
    }
}
只输出:final_parent

对应class为:
public class Main {
    public Main() {
    }

    public static void main(String[] args) {
        System.out.println("final_parent");
    }
}


例子6: 调用类的静态方法,类会初始化

public class Main {

    public static void main(String[] args) {
        System.out.println(Parent.getStatic());
    }
}

输出:
parent static code
parent static method


例子7: 通过子类调用父类的static方法,不会初始化子类

public class Main {

    public static void main(String[] args) {
        System.out.println(Sub.getStatic());
    }
}

输出:
parent static code
parent static method


如果将Sub类中的注释部分解开;
输出:
parent static code
sub static code
sub static method


例子8: new子类,会先初始化其父类

public class Main {

    public static void main(String[] args) {
        new Sub();
    }
}

输出:
parent static code
sub static code
parent init
sub init






原创粉丝点击