【问题标题】:In Java, why would a variable declared in both a parent and child class be invisible in an instance of the child class?在 Java 中,为什么在父类和子类中声明的变量在子类的实例中是不可见的?
【发布时间】:2023-03-28 04:05:01
【问题描述】:

具体来说,为什么在父类和子类中声明的变量在传递给参数为父类的方法的子类实例中是不可见的?

这是一个令我困惑的问题的简化示例。有三个类,一个父子类型和两个子子类型。这些类有一个 Foo 对象作为字段和这种静态类型的工厂方法:

class Parent {
    public Foo myFoo;

    public static ThinChild createThinChild(Foo someFoo) {
        ThinChild thinChild = new ThinChild(someFoo);
        return thinChild;
    }

    public Foo getFoo() {
        return myFoo;
    }
}

class ThinChild extends Parent {
    public Foo myFoo;

    public ThinChild(Foo someFoo) {
        myFoo = someFoo;
    }
}

class ThickChild extends Parent {
    public Foo myFoo;

    public ThickChild(Foo someFoo) {
        myFoo = someFoo;
    }
}

现在考虑这个处理程序类:

class ChildHandler {
    private void doSomethingToThinChild(ThinChild thinChild) {
        assert(thinChild.getFoo() != null);
        doSomethingToAllChildren(thinChild);
    }

    private void doSomethingToAllChildren(Parent thinOrThickChild) {
        assert(thinOrThickChild.getFoo() != null);
    }
}

当我调用doSomethingToThinChild 时,断言通过了。但是在doSomethingToAllChildren 方法中,断言失败。这不是我所期望的。

此外,如果我将与 Parent 类中相同的 getFoo 方法添加到我的 ThinChild 类中,则断言现在可以工作。这解决了我眼前的问题,但对我来说似乎不受欢迎,因为我现在在每个子类中维护相同的代码,而我更愿意在父类中维护它。

我的实际情况有点复杂,但我希望我已经掌握了所有相关的细节。假设我有,是否有任何解释为什么这是预期的行为?

在我的实际代码中可能还有一个我没有在这里表示的复杂情况。但首先我想确认一下我对 Java 中类继承的理解是正确的。

谢谢。

【问题讨论】:

  • 你的意思是class ThinChild extends Parent
  • 你不需要在嵌套类中声明public Foo myFoo;。 myFoo 已经存在了
  • 这三个类完全不相关。没有类扩展任何其他类。并且处理程序没有编译。
  • 删除嵌套类中的public Foo myFoo;。该字段从父类扩展
  • @klenwell:讨论无法编译的代码的行为没有任何意义。发布一个 SSCCE,我们将解释它的行为方式。我唯一能说的是你的处理程序的两个断言做同样的事情。

标签: java inheritance


【解决方案1】:

删除public Foo myFoo。在嵌套类中,此字段从父类扩展。您无法更改它,因为您有 2 个同名变量。所以JVM用更小的范围初始化变量。

另外一个好方法是在父级中创建构造函数:

public Parent(Foo someFoo) {
    myFoo = someFoo;
}

然后在子类中调用它:

public ThinChild(Foo someFoo) {
    super(someFoo);
}

【讨论】:

  • 删除子类中声明的字段解决了我的问题。谢谢。但我不明白为什么这很重要。您能否更新您的答案以强调这一点,并尽可能帮助我理解为什么它很重要?
  • 变量 myFoo 在嵌套类中不可见,您无法更改它,因为您有 2 个同名变量。所以JVM初始化变量的范围更小
  • 谢谢@alaster。编辑您的答案以包括您的 cmets 并选择它。
【解决方案2】:

myFoo 在直接子类中可见,您只需使用“super.myFoo”对其进行限定。不过,这只适用于链上一级。因此,如果 ThinChild 也有一个带有 myFoo 的子类 ThinnerChild,则您无法访问位于 Parent 类中的“myFoo”实例。这个想法是你应该能够覆盖你自己对父母的行为,但你不应该能够覆盖你的父母(因此为什么不允许像 super.super 这样的东西)。

话虽如此,删除子类上的实例很可能是您想要的,因为在这种情况下,每个 ThinChild 和 ThickChild 实际上都有两个“myFoo”实例,一个属于它,一个属于它的父级。

【讨论】:

    猜你喜欢
    • 2018-03-16
    • 1970-01-01
    • 1970-01-01
    • 2019-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多