java类初始化顺序的影响

问题描述:在网上看到一个笔试题,由下列代码输出打印结果为null,为什么?
详细查看http://blog.csdn.net/two_water/article/details/53891952这篇博客

package test;
public class Base {
    private String name ="base";

    public Base() {
        callName();
    }

    public void callName() {
        System.out.println(name);
    }

    static class Sub extends Base {
        private String name = "sub";

        public void callName() {
            System.out.println(name);
        }
    }

    public static void main(final String[] args) {
        Base base = new Sub();
    }

}

突然间发现自己也不是很清楚,于是阅读了上面的那篇文章,写的很好,浅显易懂。最关键的是理解下面这段代码以及构造器的初始化顺序大概是:父类静态块 ->子类静态块 ->父类初始化语句 ->父类构造函器 ->子类初始化语句 -> 子类构造器,也就清楚了代码的执行流程。

public Sub(){
    super();
    baseName = "sub"; 
}

但是一个同事看后问我,此时Base类中的name的值是什么?这由提出了另外一个问题,也就是在类的构造函数中,super()、类变量初始化、代码块中代码,他们的顺序又是怎么样?为了得出答案,我通过javap -verbose Base指令将Base.class文件打印出来查看Base.:()V的具体指令时发现了答案。
aload_0
invokespecial #1; //Method java/lang/Object.””:()V
aload_0
ldc #2; //String base
putfield #3; //Field name:Ljava/lang/String;
aload_0
invokevirtual #4; //Method callName:()V
return
从上面可以看出,一个类的构造方法的指令是从父类构造方法先执行,然后进行类变量初始化,最后才是放在构造方法中代码的执行,也即

public Base() {
     super(); //先父类构造方法
     name = "base"; //接着类变量初始化
     callName();   // 最后才是代码块的执行
} 

问题似乎得到解决,那么在来一波程序进行分析,此时答案为多少?

package test;
public class InitialClass {
    public int i = methodI();
    public static int j = methodJ();
    public int k = 0; 

    public InitialClass() {
        System.out.println(1);
    }

    public int methodI() {
        System.out.println(2);
        return 2;
    }

    public static int methodJ() {
        System.out.println(3);
        return 3;
    }

    static class B extends InitialClass {
        public int m = methodM();
        public static int n = methodN();
        public int t = 0;

        public B() {
            System.out.println(4);
        }

        public int methodM() {
            System.out.println(5);
            return 5;
        }

        public static int methodN() {
            System.out.println(6);
            return 6;
        }
    }

    public static void main(final String[] args) {
        System.out.println(7);
        InitialClass a = new B();
        a.toString();
    }
}

只要记住上面提到过的类构造器的初始化顺序大概是:父类静态块 ->子类静态块 ->父类初始化语句 ->父类构造函器 ->子类初始化语句 -> 子类构造器。一般会认为答案是
7
3
6
2
1
5
4
但是通过编译、执行发现答案是
3
7
6
2
1
5
4
依据类构造器的顺序我们可以理解3、6的顺序,那么为什么7会在3、6之间输出呢?问题似乎又变得有意思起来。其实转弯理解main方法是InitialClass类的静态方法,jvm是从InitialClass类的main作为程序入口进行执行,那么首先得加载InitialClass类,此时会初始化静态变量j,也就执行了methodJ()静态方法,在进行new B()时,此时父类InitialClass已经加载,则执行B中的静态类变量初始,在依次执行父类构造器、子类构造器从而得出结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值