我尝试了解子类型和继承在 Java 中的工作原理。最近我遇到了一个让我很困惑的情况。我得到了以下包含三个类的代码:
class Super{
String i = "Variable of superclass";
void m() {
System.out.println(i);
}
}
class Sub extends Super{
String i = "Variable of subclass";
/*@Override
void m() {
System.out.println(i);
}*/
}
public class Main {
public static void main(String[] args) {
Sub sub = new Sub();
sub.m(); //Prints Variable of superclass
}
}
我对 m() 的输出很困惑。我只是不明白为什么在 Sub 实例上调用的方法使用父类(super class)的变量。我想这与变量隐藏/阴影有关,但我无法弄清楚那里到底发生了什么。如果我做类似的事情
Super sup = new Sub();
sup.m();
然后我明白了,为什么它打印父类(super class)的变量。这是因为变量以静态方式绑定(bind),我称之为变量隐藏/阴影。但我真的不明白,在我的例子中发生了什么。
当我删除 Sub 中的评论时,我对发生的事情更加困惑。我知道该方法现在已被重写,但我不明白为什么该方法现在使用子类的变量,即使它与如果我留下注释而继承的代码完全相同。我的意思是,它已经在那里了!使用完全相同的代码重写方法会如何改变任何内容?
我还尝试在方法内添加 System.out.println(this.getClass.getName());
以确保确实在 sub 实例上调用该方法。是的,确实如此。
如果有人能帮助我理解这里发生了什么,我将非常感激!
最佳答案
方法可以被覆盖,但字段不能。 Sub
没有定义m
方法,所以sub.m();
调用m
方法来自Super
。在该方法的范围内,只有 i
Super
中定义的字段本身是可见的。
i
Sub
中定义的字段是一个不同的字段,它隐藏了同名父类(super class)的字段。如果您定义了 getI()
两者中的方法 Super
和Sub
,调用 getI()
在Super
(当底层实例的类型为 Sub
时)将使用 Sub
中定义的方法.
关于java - Java 中的子类型会导致意外的输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76838232/