Java 为什么它在子类对象中存储或分配超级类变量的内存?
在下面的代码中-Java 为什么它在子类对象中存储或分配超级类变量的内存?,java,inheritance,polymorphism,subclass,superclass,Java,Inheritance,Polymorphism,Subclass,Superclass,在下面的代码中- class Mammal { String name = "furry "; String makeNoise() { return "generic noise"; } } class Zebra extends Mammal { String name = "stripes "; String makeNoise() { return "bray"; } } public class ZooKeeper {
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
)的值
我知道在多态性中,子类也可以使用超类的泛型方法。但为什么子类对象也存储超类变量的值,即使是在隐藏的情况下。这有什么用吗 首先:一般来说,如果类定义了子类可以访问的字段,则子类不应重新定义该字段。这真是个坏主意。您看到的主要功能是使private字段正常工作。在子类中重新定义非私有字段是在寻求一个伤害的世界。(当然,如果乔写的是
哺乳动物
,玛丽写的是斑马
,乔在哺乳动物
中添加了一个字段,该字段恰好与玛丽在斑马
中使用的字段冲突,玛丽对此无能为力。这是将所有字段设置为私有的原因之一。)
但为什么子类对象也存储超类变量的值,即使是在隐藏的情况下
这里的关键是要记住字段不是多态的,只是方法。因此,对象中必须有两个名称
字段(一个来自哺乳动物
,一个来自斑马
),因为使用哺乳动物
类型引用的代码需要查看哺乳动物
名称,而使用Zebra
类型引用的代码需要查看Zebra
名称
这就是为什么你的代码显示“毛茸茸的叫声”,然后显示“条纹叫声”。您通过m
获得“furry bray”,因为在m
上访问name
(一个哺乳动物
-类型变量)访问哺乳动物
的名称
(非多态),会给您“furry”。但随后您使用m
调用方法makeNoise
,并返回“bray”
,因为调用的方法是Zebra
(多态)上的方法。然后用z
(一个Zebra
-键入的引用)再次执行此操作,并看到“条纹嘶鸣”,因为z
访问Zebra
的名称,而不是哺乳动物的
下一个问题是:如果我们将两个类中的makeNoise
更改为:
String makeNoise() {
return this.name;
}
为什么动物园管理员的代码
Mammal m = new Zebra();
System.out.println(m.name + m.makeNoise());
Zebra z = new Zebra();
System.out.println(z.name + z.makeNoise());
从m
和z
给我们提供“毛茸茸的条纹”
这是同样的原因,只是不同的表现m.name
从哺乳动物
类型的引用中访问名称
,从而查看哺乳动物
的名称
(非多态性)m.makeNoise
调用Zebra
makeNoise
方法(多态),在Zebra
内部makeNoise
,这个具有斑马
类型,即使我们从哺乳动物中调用它(因此,this.name
使用了Zebra
的name
)。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
中得到“毛茸茸的”和从z
中得到“条纹毛茸茸的”。其原因与上面相同:引用的类型决定使用哪个字段,在哺乳动物
代码中(makeNoise
),this
的类型为makeNoise
。因此,尽管我们使用z
调用了makeNoise
,但由于Zebra
没有makeNoise
,哺乳动物的类型被调用,因此查找name
的引用的类型为makeNoise
这有什么用吗
类的正常工作是至关重要的,尤其是在私有字段的情况下。哺乳动物
代码不必担心出现子类并重新定义其字段。您可以有10个深的类层次结构,每个类定义自己的名称
,这很好,每个级别的代码都可以使用它定义的名称
。没有子类对象和超类对象。只有一个对象。当你做new Zebra()
时,你会得到一个Zebra
(它本身也是哺乳动物
)。您没有得到一个Zebra
对象和另一个Madama
对象。这是因为您声明了name
两次:Zebra.name
“隐藏”Madama.name
-它不是同一个变量。请从Zebra中删除声明,并将赋值放入Madama的构造函数中以使用同一个变量(不仅仅是一个同名的)。只有一个物体,斑马也是哺乳动物,但在某个地方没有独立的哺乳动物物体,漂浮在周围。它还要把它们放在哪里?你的问题没有意义。