Java继承中方法重写、构造器行为及变量遮蔽问题咨询
问题分析:为什么输出是-1而不是1001?
我们一步步拆解代码执行的全过程,就能明白问题出在哪:
1. 先搞清楚:void Base()不是构造器!
构造器的规则是没有返回值类型,你写的void Base()是一个普通实例方法,只是名字和类名相同而已。所以父类构造器里的Base()调用的是这个普通方法,不是递归调用构造器。
2. 子类的void Base()确实重写了父类的方法
因为方法签名完全一致(返回值void、方法名Base、无参数),所以父类构造器调用Base()时,会触发动态绑定,调用子类重写后的方法——这部分你的理解是对的,但接下来的变量初始化顺序才是关键。
3. Java对象初始化的顺序(核心原因!)
当你执行new Derived()时,初始化严格遵循以下顺序:
- 先执行父类
Base的实例变量初始化:id = 1000(此时父类的id是1000) - 执行父类
Base的构造器:里面调用Base(),也就是子类的void Base()方法 - 此时子类
Derived的实例变量id还没完成显式赋值! 子类的实例变量初始化和构造器执行,必须等父类构造器完全执行完才会开始。- int类型的成员变量默认初始化值是
0,所以此时子类的id是0
- int类型的成员变量默认初始化值是
- 子类
Base()方法里执行--id:0减1得到-1,所以输出-1 - 父类构造器执行完后,才会执行子类的实例变量初始化:
id = 2000,但这时候输出已经完成了,这个赋值不影响结果
4. 为什么不是用父类的id?
变量的访问是静态绑定的,子类方法里的id默认指向子类自己的成员变量,而非父类的。如果要访问父类的id,需要用super.id,但你这里没写,所以用的是子类还没初始化完成的id。
总结:你预期的1001是假设调用父类的Base()方法操作父类的id,但实际上因为动态绑定调用了子类的方法,而子类的id此时还没赋值2000,还是默认的0,--之后就是-1。
内容的提问来源于stack exchange,提问作者happy
相关产品推荐
相关产品推荐

