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

Java继承中子类同名属性获取异常:为何返回父类值及解决方法?

这是个很典型的Java字段隐藏问题,我来给你拆解一下原因和解决方案:

问题原因

Java里和方法不一样,成员字段是不支持重写的,只能被"隐藏"。当你在子类B里定义了和父类A同名的invocations字段时,子类的这个字段并没有覆盖掉父类的版本,只是把它"藏"起来了。

这里的关键是:Java对字段的访问是编译期静态绑定的——编译器会根据你用来访问字段的引用类型来决定用哪个类的字段,而不是看实际运行时对象的类型。举个例子,如果你的代码是这么写的:

A myObj = new B();
System.out.println(myObj.invocations); // 这里会输出["foo"]

因为myObj的引用类型是A,编译器就会绑定到A类的invocations字段,哪怕实际对象是B类型的。

解决方案

想要拿到B类里的{"bar", "baz"},有几种靠谱的方式:

1. 直接用子类类型的引用访问

如果你的代码里直接用B类型的变量来持有实例,访问字段时自然会拿到子类的版本:

B myObj = new B();
System.out.println(Arrays.toString(myObj.invocations)); // 输出 [bar, baz]

2. 改用Getter方法(推荐的面向对象写法)

直接暴露字段不是好的设计,更规范的做法是用方法来返回字段值——因为方法支持重写,是运行期动态绑定的,能自动适配实际对象的类型。

修改父类A:

public class A {
    protected String invocations[] = {"foo"};

    public A() {
        // do stuff
    }

    // 添加Getter方法
    public String[] getInvocations() {
        return invocations;
    }
}

修改子类B,重写Getter方法:

public class B extends A {
    protected String invocations[] = {"bar", "baz"};

    public B() {
        super();
    }

    @Override
    public String[] getInvocations() {
        return invocations;
    }
}

现在不管你用父类还是子类引用,都能拿到正确的结果:

A myObj = new B();
System.out.println(Arrays.toString(myObj.getInvocations())); // 输出 [bar, baz]

3. 向下转型(不推荐,尽量避免)

如果已经有了父类类型的引用,可以先判断类型再向下转型,然后访问子类字段,但这种写法不够安全,万一对象不是B类型会抛出ClassCastException:

A myObj = new B();
if (myObj instanceof B) {
    System.out.println(Arrays.toString(((B) myObj).invocations)); // 输出 [bar, baz]
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 03:42:52