【问题标题】:Variable shadowing in Java [duplicate]Java中的变量阴影[重复]
【发布时间】:2013-06-05 13:26:01
【问题描述】:

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

  1. 为什么我会得到这个输出?
  2. 如何在 ZooKeeper 类中访问字符串对象引用“name”?
  3. 如果它与变量阴影有关,那么阴影是哪个变量?

代码:

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

【问题讨论】:

标签: java


【解决方案1】:

变量不是多态的。当您访问m.name 时,将始终使用作为该对象一部分的Mammal.name 字段,而不管对象的执行时间类型如何。如果你需要访问Zebra.name,你需要一个compile-time类型为Zebra的表达式。

makeNoise 方法实际上是被调用的——执行时使用的实现确实取决于对象的类型。

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

这实际上是隐藏而不是阴影。有关隐藏的详细信息,请参阅JLS section 8.3,有关阴影的详细信息,请参阅 section 6.4.1。我不能说我总是直截了当...

【讨论】:

  • 所以,为了正确的输出,你必须创建一个像public String getName(){return this.name;}这样的getter方法
  • 是的,我就是这么想的。您也需要在 Zebra 中创建该吸气剂。
  • @JonSkeet - 谢谢......我从来不知道......有一种叫做隐藏变量的东西。 :)
  • @LuigiEdlCarno 在基类中为name 创建受保护字段name 和公共getter 并在派生类的构造函数中分配name,而不是覆盖getter 不是更好吗?我发现这更合乎逻辑并且节省了一些按键。
  • @PLB:好吧,我会把它设为超类中的 private 字段——但这取决于需要什么。我们在这里并没有真正的用例,并解释了这两个独立字段的含义。
【解决方案2】:

输出为“毛茸茸的布雷”。请解释一下。

java 程序中的fields 不能通过动态查找访问。相反,它们在编译时被静态解析。这就是为什么您会为m.name 获得furry。然而,Java 程序中的methods 是通过动态查找访问的。这就是为什么您会为m.makeNoise() 获得bray

我们如何访问 name 变量,其中有“条纹” 是吗?

如果你想访问 Zebra.name ,你应该输入 cast m to 'Zebra'。这看起来像这样:

System.out.println(((Zebra)m).name + m.makeNoise());

更新
这里展示的现象是Fields Hiding 而不是variable shadowing 的结果。

【讨论】:

    【解决方案3】:

    在 Java 中没有变量覆盖,您在父项和子项中都声明了 name,但您通过父引用变量引用它。这就是你得到“毛茸茸”的原因。

    方法有重载,这就是为什么你有 bray。因为在运行时它查看了堆中的真实对象,发现它是 Zebra。

    【讨论】:

      【解决方案4】:

      Java 中的变量名由引用类型解析,而不是它们所引用的对象。所以,m.name 指的是 Mammal 中的变量名,即使面团 m 是 Zebra。

      【讨论】:

        【解决方案5】:

        这是因为 Mammal 中的 name 字段被 Zebra 中的 name 字段隐藏。然后,您只需转换为所需类型即可访问它。
        另一方面,makeNoise() 方法 覆盖 来自父级的相同方法,因此您无法再从父级访问实现。

        【讨论】:

          猜你喜欢
          • 2018-03-05
          • 2016-01-04
          • 2013-02-25
          • 1970-01-01
          • 2013-06-13
          • 2013-06-15
          • 1970-01-01
          • 1970-01-01
          • 2010-11-08
          相关资源
          最近更新 更多