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

关于父子构造器初始化子类对象及同名成员变量的疑问

子类继承父类后同名变量的困惑

我了解到,当子类继承父类并创建子类对象时,子类构造器会隐式调用super()自动触发父类构造器。此时仅会创建一个对象,父类构造器负责初始化继承自父类的属性,子类构造器负责初始化子类特有的属性。但如下示例让我产生困惑:

父类代码:

public class P
{
    int x;

    P(){
        x = 1;
    }
    public int getX(){
        return x;
    }
}

子类代码:

public class C extends P
{
    int x;

    C(){
        x = 2;
    }
    public static void main(String[] args)
    {
        C c = new C();
        System.out.println("c.x: " + c.x);
        System.out.println("c.getX(): " + c.getX());
    }
}

输出结果:

c.x: 2
c.getX(): 1

我十分困惑:明明只创建了一个对象,为何会存在两个同名的x变量?若子类隐藏了父类的x变量,为何会得到不同的输出?父类和子类读取的x究竟来自哪里?还请帮忙解惑。


核心原因:Java的**变量隐藏(Field Hiding)**机制

下面逐个解答你的疑问:

  1. 为什么一个对象里会有两个x?
    子类继承父类时,会继承父类的所有非私有成员变量,包括P类的x。但当子类C自己声明了同名的x时,这并不是"覆盖"父类的变量(覆盖只针对方法),而是隐藏了父类的x。此时这个C对象的内存结构中,同时包含两部分:

    • 父类P的成员区域:存储着被隐藏的x(值为1)
    • 子类C的成员区域:存储着自己声明的x(值为2)
      两者属于同一个对象的不同内存区域,共存但互不干扰。
  2. 为什么c.x和c.getX()输出不同?

    • 直接访问c.x时,编译器会根据引用的静态类型(这里是C)来解析变量,优先使用子类中声明的x,所以输出2。
    • getX()方法是父类P定义的,子类没有重写这个方法。当调用c.getX()时,方法内部的x是在父类的上下文里解析的,它只会访问父类区域的x(也就是被隐藏的那个),所以返回1。如果子类重写getX(),比如:
      @Override
      public int getX() {
          return x; // 这里的x是子类自己的x
      }
      
      此时调用c.getX()就会返回2。
  3. 如何直接访问被隐藏的父类变量?
    在子类中可以通过super.x来显式访问父类被隐藏的变量,比如给C类加一个方法:

    public int getParentX() {
        return super.x;
    }
    

    调用c.getParentX()会返回1,这就验证了父类的x确实存在于同一个对象中。

关键总结

  • 变量隐藏是编译时行为:编译器根据引用的静态类型决定访问哪个变量;
  • 方法覆盖是运行时行为:JVM根据对象的实际类型决定调用哪个方法;
  • 子类对象包含父类的所有非私有成员,同名变量只是被隐藏,而非被替换或删除。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 21:05:19