我确信每天都会问这类问题,但我正在努力理解为什么哺乳动物被实例化为猫,并将其名称报告为莫里斯。然而,与大多数猫不同,它没有9条生命。如果对象不是猫,为什么它的名字是莫里斯?
class Mammal {
int temp;
String name = "George";
public Mammal() {
temp = 98;
}
public String getName() {
return name;
}
}
class Cat extends Mammal {
int lives;
String name = "Morris";
public Cat() {
lives = 9;
}
public String getName() {
return name;
}
}
public class Inheritance {
public static void main(String[] args) {
Mammal mm = new Cat();
System.out.println("Mam Temp:" + mm.temp);
//System.out.println("Cat Lives:" + mm.lives); <-- error
System.out.println("Mam Name:" + mm.getName());
}
}
答案 0 :(得分:3)
这里有两个相关但具体分开的概念。
对象的运行时类型将决定它在运行时的行为方式。它取决于您在使用new
关键字时调用的构造函数。
变量的静态类型决定了代码如何与变量(以及它引用的对象)进行交互或引用。当您声明该变量(或字段,参数等)时,它由您指定的类型决定。
在这种情况下,变量的静态类型为Mammal
,而它指向的对象的运行时类型为Cat
。因此,虽然它在运行时表现得像Cat
并且显示其名称为'Morris',但在编译时编译器只知道它是Mammal
,并且不能引用lives
变量(在Cat
中定义,而不是Mammal
)。
答案 1 :(得分:2)
因为变量属于Mammal
类型,它在行Mammal mm = new Cat();
中设置。 Mammal
类不包含变量lives
,因此会抛出错误。但是,如果您执行((Cat)mm).lives
,则应该得到正确的结果,因为您将mm
变量强制转换为类型Cat
(它已初始化为)。
修改强>
此外,您覆盖getName()
类中的Cat
方法,该方法“隐藏”Mammal
类中的方法。您创建mm
作为类型Mammal
,但实际上它是Cat
,因此调用getName()
上的mm
方法将调用子方法{{1} }}返回getName()
而不是"Morris"
。
答案 2 :(得分:1)
您创建了Cat
的实例,但您将其视为Mammal
。 Mammal.lives
不存在,这就是您尝试打印mm.lives
时出现错误的原因。
顺便说一句,这是一个很好的例子,说明为什么继承可能是危险的,应该谨慎使用。 Cat和Mammal通过继承紧密耦合,因此您必须了解类及其交互方式才能理解处理Cat
的代码。
答案 3 :(得分:1)
创建的对象是Cat的对象,因此调用时的getName方法位于Cat对象上,因此其名称报告为“morris”。然而,局部变量被定义为哺乳动物,因此除非您明确地将其投射到猫身上,否则无法访问生命。