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

Java中子类和父类存在同名属性时的运行机制疑问

Java父子类同名属性调用规则解析

你提供的测试代码如下:

public class Test {
    public static void main(String[] args) {
        B b = new B();
        b.test();
    }
}

class A {
    String aString = "a";
    
    void test() {
        System.out.println(aString);
    }
}

class B extends A {
    String aString = "b";
}

核心结论

Java中属性不存在重写机制,只有隐藏特性,方法才支持重写(动态分派),这是出现该输出的根本原因。

具体运行规则

  • 方法调用的动态分派:你调用new B().test()时,因为B类没有重写父类A的test()方法,所以实际执行的是A类中定义的test()方法逻辑。
  • 属性引用的静态绑定:类方法中引用的属性,是在编译期就和当前方法所属的类绑定的,不会根据调用方法的实例类型动态切换。A类的test()方法中的aString,编译时就已经绑定为A类自己的aString属性,值为"a",因此最终输出为"a"。
  • 子类同名属性的本质:B类定义的aString只是隐藏了父类的同名属性,并非覆盖。B类的实例在内存中实际上会保留两份aString属性,分别属于父类A和子类B。如果要在子类代码中访问父类的同名属性,需要用super.aString显式指定,但父类方法中不会主动访问子类定义的同名属性。

拓展:如何实现输出"b"的预期效果

方案1:子类重写test()方法

class B extends A {
    String aString = "b";
    
    @Override
    void test() {
        // 该方法属于B类,编译期绑定B类的aString属性
        System.out.println(aString);
    }
}

方案2:使用getter方法利用动态分派特性

属性是静态绑定,但方法是动态分派的,因此可以通过定义公共的getter方法实现预期效果:

class A {
    String aString = "a";
    
    // 定义getter方法
    public String getaString() {
        return aString;
    }
    
    void test() {
        // 调用getter方法,会根据实例类型动态分派
        System.out.println(getaString());
    }
}

class B extends A {
    String aString = "b";

    // 重写getter方法
    @Override
    public String getaString() {
        return aString;
    }
}

以上两种方案执行new B().test()都会输出"b"。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 22:12:00