今天看到一段很神奇的代码,还没闹明白,先备份一个。
父类:
class SuperClass { public int mSuperX = 1; public SuperClass(){ setX(100); } public SuperClass(int x) { setX(x); } public void setX(int x) { System.out.println("调用了父类的setX方法,赋值为:" + x); mSuperX = x; } }
子类:
class SubClass extends SuperClass { public int mSubX = 1; public SubClass() {} public SubClass(int x) { super(x); } @Override public void setX(int x) { super.setX(x); mSubX = x; System.out.println("调用了子类的setX方法,赋值为:" + x); } public void printX() { System.out.println("SubX = " + mSubX); } }
测试类:
public static void main(String[] args) { // TODO Auto-generated method stub SubClass sc = new SubClass(111); System.out.println(sc.mSuperX); System.out.println(sc.mSubX); sc.printX(); }
结果:
调用了父类的setX方法,赋值为:111 调用了子类的setX方法,赋值为:111 111 1 SubX = 1
很神奇。。。 子类的set赋值方法调用了父类的set方法,然后执行自己的赋值方法。父类的值已经变了,但是子类的值没有变化。。 还是1. 但是,把子类的初始化去掉,改为public int mSubX;执行结果就是正确的111。。
这就要牵扯到jvm的底层实现了。。。 目前还没搞清楚,只有上网上搜的资料形成自己的理解,不一定对:
首先,多态调用的顺序是:1.父类static块 -> 2.子类static块 ->3. 父类普通成员初始化和初始化块 -> 4.父类构造方法 -> 5.子类普通成员初始化和初始化块 -> 6.子类构造方法。
就像这次遇到的这个问题,把子类的si赋值的语句发生在4,即调用父类构造函数的时候发生的。赋值完成后si的值确实变成了111,但是瞬间,5开始执行,si又被赋值成了1,于是111被覆盖了。
相当于 int si; si=1; 中间被插入了si=111;这么个语句。。。
至于只有int si的时候,为什么si的值没有被0覆盖。。 网上的说法是静默初始化(即不给值的初始化),在给变量赋值初始化的时候会判断变量是否没有被初始化,即变量不会被初始化两次。。 相当于int si;si=0;这两个语句中间插入了si=111只有,si=0不再执行了。。。 具体再往下深挖就是jvm底层实现的东西了。。。 现在的水平不够。。只能考虑到这了