有人可以解释一下我有点困惑的 Java upcast 行为吗?

Can someone please explain this Java upcasting behavior I am little confused?

提问人:Ajinkya Ronghe 提问时间:8/13/2023 最后编辑:Ajinkya Ronghe 更新时间:8/13/2023 访问量:67

问:

在下面给出的代码中,当我们尝试通过在打印 x.i java 时通过调用子类的构造函数来启动 A 类型的对象,以及为什么当通过方法调用它时它引用子类属性时,我无法清楚地理解 upcast 在这里是如何工作的。

代码如下:

public class Main
{
    public static void main(String[] args) {
        A x = new B();
        System.out.println(x.i);
        System.out.println(x.shout());
    }
}

class A{
    int i = 10;
    int shout(){
        return i;
    }
}

class B extends A{
    int i = 20;
    int shout(){
        return i;
    }
}
Following is the output:
10
20
Java 继承 类型 上转换

评论

1赞 Oleksandr Pyrohov 8/13/2023
这回答了你的问题吗?Java 方法覆盖和变量遮蔽
0赞 Reilas 8/13/2023
这些字段用于向类提供数据,而不一定是类外部的数据。一种看待它的方式是,继承是代码功能的概念,而不一定是值。您应该期望字段需要显式语法,并且方法在逻辑上优先。包含数据的方法有很多种,但数据可能看起来不符合基本继承,但这并不意味着这是不可能的。

答:

1赞 KpekepSalt 8/13/2023 #1

当子类的字段与超类的字段同名时,它被称为 - 隐藏字段。Java 不支持字段的多态性。

因此,在您的示例中,将调用重写的方法,并因此使用子字段。但是,当通过父类直接访问时,将使用父类的字段。

public class Main
{
    public static void main(String[] args) {
        A x = new B();
        System.out.println(x.i); // Uses A.i
        System.out.println(x.shout()); // Uses B.shout()
    }
}
2赞 Andreas Lundgren 8/13/2023 #2

这是因为在子类中重新定义 Java 中的方法会被覆盖,但属性会被遮蔽。因此,只有一种方法可用,但有两个实际属性 ishout()

在实际案例中,如果需要使用相同的名称,则可以将属性定义为私有。然后,您将使用 getter 显式处理选择要访问的 getter(就像 i 的 getter 一样)。或者至少通过将 i 投射到正确的类来明确指出 i 是什么。如果您仍然希望将一个公共属性与另一个具有相同名称的属性隐藏在一起,您仍然可以将它们引用为或选择正确的属性。shout()super.ithis.i

1赞 WJS 8/13/2023 #3

您分配了一个 to 的实例,因此您使用的是重写的方法,该方法在调用该方法时也使用 instance 字段 of。它类似于闭包,因为它封装了 B 的 版本。当直接访问 A 的版本时,你得到的版本,从 A 的角度来看,它是没有阴影的。BAB'sB'siiiA's

如果要访问 from 方法的版本,可以执行以下操作:A'siB'sshout()

class B extends A{
    int i = 20;
    int shout(){
        return super.i;
    }
}

使用您当前的调用,您将获得

10
10

这还有很多。有关更多信息,请查看 继承、覆盖和隐藏Java Language Specification