Java继承场景下父类Base调用tellName/printName为何输出null
Java继承构造调用输出异常原因解析
涉及核心规则
- Java创建子类实例时的固定执行顺序:
- 为父类、子类的所有成员变量分配内存空间,统一赋予类型默认初始值(引用类型默认
null,整数类型默认0,布尔类型默认false) - 递归调用顶层父类的构造方法,直到
Object类,再逐层向下执行父类构造逻辑 - 父类构造全部执行完成后,才会执行子类成员变量的显式赋值语句(比如代码中
private String name = "dervied";的赋值动作) - 最后执行子类自身构造方法内的代码
- 为父类、子类的所有成员变量分配内存空间,统一赋予类型默认初始值(引用类型默认
- Java普通实例方法(非
private、非static、非final修饰)采用动态绑定机制:方法调用的实际版本以运行时对象的实际类型为准,哪怕调用位置在父类构造方法中,只要子类重写了对应方法,就会优先执行子类重写的版本
执行流程对应输出拆解
测试代码如下:
public class Dervied extends Base{ private String name = "dervied"; public Dervied(){ tellName(); printName(); } public void tellName(){ System.out.println("Dervied tell name: " + name); } public void printName(){ System.out.println("Dervied print name: " + name); } public static void main(String[] args){ new Dervied(); } } class Base{ String str = "base"; public Base(){ tellName(); printName(); } public void tellName(){ System.out.println("Base tell name: " + str); } public void printName(){ System.out.println("Base print name: " + str); } }
实际运行输出:
Dervied tell name: null Dervied print name: null Dervied tell name: dervied Dervied print name: dervied
逐段对应执行逻辑:
- 执行
new Dervied()时,首先为Base类的str、Dervied类的name分配内存,两者作为引用类型初始值都是null - 自动触发父类
Base的无参构造执行:构造方法内调用的tellName()、printName()已经被子类Dervied重写,动态绑定到子类的方法版本。此时子类的name还未执行显式赋值,仍然是初始值null,因此输出前两行null的结果 - 父类构造执行完毕后,开始执行子类成员变量的显式赋值:
name被赋值为"dervied" - 执行子类
Dervied自身构造方法内的tellName()、printName()调用,此时name已经完成赋值为"dervied",因此输出后两行带dervied的结果
开发注意事项
不要在构造方法中调用可被子类重写的普通实例方法,这类调用会触发未初始化完全的子类方法逻辑,极易引发空指针、业务逻辑错误等问题。如果需要在构造中调用方法,优先调用private、static或者final修饰的不可重写方法。
内容的提问来源于stack exchange,提问作者Mark Chen
相关产品推荐
相关产品推荐

