此 Java 行为背后的推理 [重复]

Reasoning Behind this Java Behaviour [duplicate]

提问人:Alden Luthfi 提问时间:6/4/2023 更新时间:6/4/2023 访问量:53

问:

上下文

假设我们有一个这样的类继承结构

class A {
    int z = 10;

    public void display() {
        System.out.println("A's z is " + z);
    }
}

class B extends A {
    int z = 20;

    public void display() {
        System.out.println("B's z is " + z);
    }

    public void onlyB() {
        System.out.println("This is only in B");
    }
}

class Main {

    public static void main(String args[]) {
        A obj = new B();

        System.out.println(obj.z); // 10
        obj.display(); // B's z is 20
    }
}

问题

为什么给出 's 但使用 's,有没有办法考虑这个问题,使其在逻辑上有意义?obj.zAzobj.display()Bz

试图暗化

通过说

A obj = new B();

在我看来,这是在说“创建一个 A 类型的对象,但使用 B 的所有实现”

根据这个推理,对象不能使用是合乎逻辑的,因为它是 类型,并且没有 。同样通过这个推理,将使用 的实现。但是为什么调用使用 's 而不是 's?对象不应该使用 的实现吗?onlyB()AAonlyB()display()BzAzBBz

我知道这在实践中不会出现,但我很好奇。如果能更好地解释为什么会发生这种情况,将不胜感激。

Java OOP 继承 类型 转换

评论


答:

1赞 Elliott Frisch 6/4/2023 #1

您已经引入了可变阴影。该字段不同于 (并继承,但隐藏了 )。但是,如果您将其从B.zA.zA.z

class B extends A {
    int z = 20;

到类似的东西

class B extends A {
    public B() {
        this.z = 20;
    }

那么它实际上是继承,只会有一个.z

1赞 Amir Pashazadeh 6/4/2023 #2

在 Java(以及我所知道的大多数语言)中,字段不会被覆盖。因此,如果您在父类中定义一个字段,并在子类中定义一个同名的其他字段,则这两个字段都将存在在那里(并且每个字段都可以在其类中正常访问)。(考虑将 your in 定义为 String not int!,现在它们有不同的类型,并且看到一个 String )。zBBz

但是非静态方法可以被覆盖。

当你有一个实例时,你有一个 的实例,但引用类型为 A。当访问字段(不可覆盖)时,则 你正在访问 ,但是当你调用方法(被覆盖)时,通过 a 和 B 的方法调用查找的真正方法被调用(这就是继承的力量),并且该方法访问它自己的方法。(再次考虑在 B 中为 ,则 int 类型不是 String 类型,后者位于 的类型类中)。A obj = new B()BA.zdynamic lookup tablezzStringobj.zobj