Java中的变量阴影

时间:2013-06-05 13:26:02

标签: java

我对这个Java代码有些怀疑。它给出的输出是“毛茸茸的bray”。我的问题:

  1. 为什么我得到这个输出?
  2. 如何在ZooKeeper类中访问String对象引用“name”?
  3. 如果它与变量阴影有关,那么哪个变量被遮蔽?
  4. 代码:

    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?
       }
     }
    

5 个答案:

答案 0 :(得分:63)

变量不是多态的。当您访问m.name时,总是使用属于该对象的Mammal.name字段,而不管对象的执行时类型。如果您需要访问Zebra.name,则需要一个编译时类型为Zebra的表达式。

虚拟调用makeNoise方法 - 执行时使用的实现取决于对象的类型。

请注意,如果您将所有字段设为私有 - 无论如何这通常是一个好主意 - 这不会成为问题。

这实际上是隐藏而不是阴影。有关隐藏的详细信息,请参阅JLS section 8.3,有关隐藏的详细信息,请参见section 6.4.1。我不能说我总是保持差异......

答案 1 :(得分:15)

  

输出来自“毛茸茸的bray”。请解释一下。

不能通过动态查找访问java程序中的

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方法覆盖来自父级的相同方法,因此您无法再从父级访问实现。