Java中初始化final字段时的异常行为问题
为什么子类final字段在父类构造器调用的重写方法中显示为null?
这是Java初始化过程中一个很容易踩的经典陷阱,咱们结合你的代码一步步拆解原因:
首先得明确Java实例化子类对象时的执行顺序:
- 当你调用
new Test2()时,JVM先处理子类的静态初始化(你的代码里没有静态成员,直接跳过)。 - 进入
Test2的构造器,第一行显式调用super(),此时会优先执行父类Test的构造器。 - 父类构造器里调用了
foo()方法,而foo()是抽象方法,已经被Test2重写,所以实际执行的是子类Test2中的foo()实现。 - 核心问题就在这里:此时
Test2的实例成员testObj还没完成初始化!子类的实例成员(哪怕是声明时直接赋值的final字段),都是在父类构造器执行完成之后才会被初始化的。 - 所以当
foo()打印testObj时,它还处于默认的null状态——final修饰符只是保证字段一旦赋值就不能被修改,但它依然要遵守Java的初始化顺序规则,此时还没到它的赋值时机。
再给你拆解开Test2的初始化细节:编译器会自动把你在声明时赋值的final字段,移到子类构造器的super()之后、构造器其他代码之前,相当于你的Test2构造器实际是这样的:
public Test2() { super(); // 先执行父类构造器,此时调用子类foo(),testObj还没赋值 testObj = new Object(); // 这行是编译器自动添加的,在super()之后才执行 }
关键总结
永远不要在父类构造器中调用可被重写的方法(包括抽象方法、非final的实例方法),这会导致子类的方法在子类实例成员完成初始化之前被执行,从而访问到未初始化的成员,引发意料之外的错误。
内容的提问来源于stack exchange,提问作者Simiil
相关产品推荐
相关产品推荐

