java类初始化顺序的影响

来源:互联网 发布:微盘外汇交易平台源码 编辑:程序博客网 时间:2024/06/07 20:08

问题描述:在网上看到一个笔试题,由下列代码输出打印结果为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中的静态类变量初始,在依次执行父类构造器、子类构造器从而得出结果。

0 0
原创粉丝点击