You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java继承场景下父类Base调用tellName/printName为何输出null

Java继承构造调用输出异常原因解析

涉及核心规则

  • Java创建子类实例时的固定执行顺序:
    1. 为父类、子类的所有成员变量分配内存空间,统一赋予类型默认初始值(引用类型默认null,整数类型默认0,布尔类型默认false)
    2. 递归调用顶层父类的构造方法,直到Object类,再逐层向下执行父类构造逻辑
    3. 父类构造全部执行完成后,才会执行子类成员变量的显式赋值语句(比如代码中private String name = "dervied";的赋值动作)
    4. 最后执行子类自身构造方法内的代码
  • 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

逐段对应执行逻辑:

  1. 执行new Dervied()时,首先为Base类的str、Dervied类的name分配内存,两者作为引用类型初始值都是null
  2. 自动触发父类Base的无参构造执行:构造方法内调用的tellName()、printName()已经被子类Dervied重写,动态绑定到子类的方法版本。此时子类的name还未执行显式赋值,仍然是初始值null,因此输出前两行null的结果
  3. 父类构造执行完毕后,开始执行子类成员变量的显式赋值:name被赋值为"dervied"
  4. 执行子类Dervied自身构造方法内的tellName()、printName()调用,此时name已经完成赋值为"dervied",因此输出后两行带dervied的结果

开发注意事项

不要在构造方法中调用可被子类重写的普通实例方法,这类调用会触发未初始化完全的子类方法逻辑,极易引发空指针、业务逻辑错误等问题。如果需要在构造中调用方法,优先调用private、static或者final修饰的不可重写方法。

内容的提问来源于stack exchange,提问作者Mark Chen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.02 09:27:32