为什么它在子类对象中为超类变量存储或分配内存?
在以下代码中 –
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的调试窗口中看到,两个对象( m
和z
)都包含name
变量( furry
和stripes
)的值。
我明白在多态性中,超类的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
类型的变量)访问Mammal
的name
(不是多态),给你“毛茸茸”。 但是你用m
调用方法makeNoise
然后回来"bray"
makeNoise
"bray"
,因为被调用的方法是Zebra
(多态)。 然后你用z
(一个Zebra
-typed参考)再次做到这一点并看到“条纹bray”因为z
访问Zebra
的name
,而不是Mammal
的name
。
您可能遇到的下一个问题是:如果我们将两个类中的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.name
从Mammal
-typed引用中访问name
,因此可以看到Mammal
的name
(不是多态的)。 m.makeNoise
调用Zebra
的 makeNoise
方法(多态),在Zebra
的makeNoise
, this
有Zebra
类型,即使我们从Mammal
-typed m
调用它(因此this.name
使用Zebra
的name
)。 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
。