为什么它在子类对象中为超类变量存储或分配内存?

在以下代码中 –

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

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

我明白在多态性中,超类的generics方法也可以被子类使用。 但是,为什么子类对象也存储超类变量的值,即使在隐藏的情况下也是如此。 这有什么用吗?

第一 :作为一般规则,如果类定义了子类可以访问的字段,则子类不应重新定义该字段。 这只是一个真正糟糕的主意。 你所看到的主要是让私人领域正常运作。 重新定义子类中的非私有字段是为了要求一个受伤的世界。 (当然,如果Joe写Mammal和Mary写Zebra并且在某些时候Joe为Mammal添加了一个与Mary在Zebra使用的字段冲突的字段,那么Mary就无法做到这一点。这是制作所有字段的原因之一私人的。)

但是,为什么子类对象也存储超类变量的值,即使在隐藏的情况下也是如此。

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

这就是为什么你的代码显示“毛茸茸的bray”然后“条纹bray”。 你可以通过m获得“毛茸茸的bray”,因为访问m name (一个Mammal类型的变量)访问Mammalname (不是多态),给你“毛茸茸”。 但是你用m调用方法makeNoise然后回来"bray" makeNoise "bray" ,因为被调用的方法是Zebra (多态)。 然后你用z (一个Zebra -typed参考)再次做到这一点并看到“条纹bray”因为z访问Zebraname ,而不是Mammalname


您可能遇到的下一个问题是:如果我们将两个类中的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()); 

z m stripes stripes给我们“毛茸茸的条纹”?

这也是同样的原因,只是对它的不同表现。 m.nameMammal -typed引用中访问name ,因此可以看到Mammalname (不是多态的)。 m.makeNoise调用Zebra makeNoise方法(多态),在ZebramakeNoisethisZebra类型,即使我们从Mammal -typed m调用它(因此this.name使用Zebraname )。 Zebra的makeNoise在那里使用的事实,以及Zebra代码中的类型Zebra this事实都是Java中多态性的关键。

让我们进一步说明:如果Zebra没有定义makeNoise怎么办?

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

现在我们从m得到“毛茸茸的毛茸茸”,从z得到“条纹毛茸茸”。 它的原因与上面相同:引用的类型决定了使用哪个字段,而在Mammal代码( makeNoise )中, this的类型为Mammal 。 因此,即使我们使用z调用makeNoise ,因为Zebra没有makeNoise ,所以调用Mammal ,所以查找name的引用具有类型Mammal

这有什么用吗?

课程正常工作至关重要 ,特别是在私人领域。 Mammal代码不必担心出现的子类并重新定义其字段。 你可以有一个10深的类层次结构,每个类定义自己的name ,没关系,每个级别的代码都使用它定义的name