类初始化

加载阶段,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






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值