我对这个Java代码有些怀疑。它给出的输出是“毛茸茸的bray”。我的问题:
class Mammal {
String name = "furry ";
String makeNoise() { return "generic noise"; }
}
class Zebra extends Mammal {
String name = "stripes ";
String makeNoise() { return "bray"; }
}
public class ZooKeeper {
public static void main(String[] args) { new ZooKeeper().go(); }
void go() {
Mammal m = new Zebra();
System.out.println(m.name + m.makeNoise());
//Output comes as "furry bray". Please explain this.
//And how can we access the name variable, the one having "stripes " in it.
//Does it have something to do with Variable Shadowing?
}
}
答案 0 :(得分:63)
变量不是多态的。当您访问m.name
时,总是使用属于该对象的Mammal.name
字段,而不管对象的执行时类型。如果您需要访问Zebra.name
,则需要一个编译时类型为Zebra
的表达式。
虚拟调用makeNoise
方法 - 执行时使用的实现取决于对象的类型。
请注意,如果您将所有字段设为私有 - 无论如何这通常是一个好主意 - 这不会成为问题。
这实际上是隐藏而不是阴影。有关隐藏的详细信息,请参阅JLS section 8.3,有关隐藏的详细信息,请参见section 6.4.1。我不能说我总是保持差异......
答案 1 :(得分:15)
不能通过动态查找访问java程序中的输出来自“毛茸茸的bray”。请解释一下。
fields
。相反,它们在编译时静态解析。这就是为furry
获取m.name
的原因。然而,通过动态查找访问java程序中的methods
。这就是为bray
获取m.makeNoise()
的原因。
我们如何访问名称变量,其中包含“条纹” 它?
如果你想访问Zebra.name
,你应该输入cast m
到'Zebra'。这看起来像这样:
System.out.println(((Zebra)m).name + m.makeNoise());
<强>更新强>
这里展示的现象是Fields Hiding而不是variable shadowing的结果。
答案 2 :(得分:9)
Java中没有变量覆盖,您在父级和子级中都声明了名称,但是您通过父引用变量引用了它。这就是你为什么“毛茸茸”的原因。
方法有压倒性优势,这就是为什么你会吵架的原因。因为在运行时它会查看堆中的真实对象并看到它是Zebra。
答案 3 :(得分:4)
Java中的变量名称由引用类型解析,而不是它们引用的对象。因此,m.name是指Mammal中的变量名称,即使面团m是Zebra。
答案 4 :(得分:3)
之所以发生这种情况,是因为来自name
的{{1}}字段Mammal
只是来自name
的{{1}}字段隐藏。然后,您可以通过转换为所需类型来访问它
另一方面Zebra
方法覆盖来自父级的相同方法,因此您无法再从父级访问实现。