为什么它在 sub class 对象中为 super class 变量存储或分配内存?

Why does it store or allocate memory for super class variables, in sub class object?

在下面的代码中-

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());

      Zebra z = new Zebra();
      System.out.println(z.name + z.makeNoise());
   }
}

两个对象(mz),如果我在 eclipse 的调试 windows 中看到,包含 name 变量的两个值(furrystripes)。

我知道在多态性中,super class 的泛型方法也可以被 sub class 使用。但是为什么 sub class 对象也存储 super class 变量的值,即使在隐藏的情况下也是如此。这个有什么用吗?

首先:作为一般规则,如果class定义了子class可以访问的字段,子class 不应重新定义字段。这只是一个非常糟糕的主意。您所看到的主要是为了让 private 字段正常工作。在 subclass 中重新定义非私有字段是在自寻死路。 (当然,如果乔写 Mammal 而玛丽写 Zebra 并且在某个时候乔向 Mammal 添加了一个字段,该字段恰好与玛丽在 Zebra 中使用的字段冲突, Mary 对此无能为力。这就是将所有字段设为私有的原因之一。)

But why does sub class object stores values of super class variables as well, even in case of hiding.

这里的关键是要记住字段不是多态的,只是方法。因此 对象中有两个 name 字段(一个来自 Mammal,一个来自 Zebra),因为代码使用 Mammal 类型的引用需要查看 Mammal name,而使用 Zebra 类型的引用的代码需要查看 Zebra name.

这就是为什么您的代码显示 "furry bray",然后显示 "stripes bray"。您通过 m 获得 "furry bray",因为在 m 上访问 name(一个 Mammal 类型的变量)会访问 Mammalname (不是多态的),给你 "furry"。但是随后您使用 m 调用方法 makeNoise 并返回 "bray",因为被调用的方法是 Zebra 上的方法(多态)。然后你用 z (一个 Zebra 类型的引用)再做一次并看到 "stripes bray" 因为 z 访问 Zebraname,而不是Mammal的。


您可能有的下一个问题是:如果我们将 class 中的 makeNoise 更改为:

String makeNoise() { 
    return this.name;
}

为什么ZooKeeper的代码

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

  Zebra z = new Zebra();
  System.out.println(z.name + z.makeNoise());

给我们 m 的 "furry stripes" 和 zstripes stripes?

道理是一样的,只是表述方式不同而已。 m.nameMammal 类型的引用访问 name,因此看到 Mammalname(非多态)。 m.makeNoise 调用 Zebra makeNoise 方法(多态),并在 ZebramakeNoise 内部,this 具有类型 Zebra,即使我们从 Mammal 类型的 m 调用它(因此 this.name 使用 Zebraname).那里使用 Zebra 的 makeNoise 的事实,以及 Zebra 代码中的 this 键入 Zebra 的事实都是 Java 中多态性的关键。

让我们更进一步:如果 Zebra 根本没有定义 makeNoise 怎么办?

class Mammal {
    String name = "furry ";
    String makeNoise() { 
        return this.name;
    }
}

class Zebra extends Mammal {
    String name = "stripes ";
}

现在我们从 m 得到 "furry furry",从 z 得到 "stripes furry"。而其原因同上:引用的类型决定了使用哪个字段,在Mammal代码中(makeNoise),this的类型是Mammal.因此,即使我们使用 z 调用了 makeNoise,由于 Zebra 没有 makeNoise,因此调用了 Mammal,因此查找 [=17] 的引用=] 的类型为 Mammal.

Is there any use of this?

到 class 的正常工作非常重要,尤其是在私有字段的情况下。 Mammal 代码不必担心子class 出现并重新定义其字段。您可以有一个 10 层深的 class 层次结构,每个 class 定义自己的 name,这很好,每个级别的代码都与它定义的 name 一起工作。