YAIC(又一个继承混乱)

时间:2011-10-28 16:47:27

标签: java

我确信每天都会问这类问题,但我正在努力理解为什么哺乳动物被实例化为猫,并将其名称报告为莫里斯。然而,与大多数猫不同,它没有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());  
    }
}

4 个答案:

答案 0 :(得分:3)

这里有两个相关但具体分开的概念。

  1. 对象的运行时类型。
  2. 变量的静态(和运行时)类型。
  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的实例,但您将其视为MammalMammal.lives不存在,这就是您尝试打印mm.lives时出现错误的原因。

顺便说一句,这是一个很好的例子,说明为什么继承可能是危险的,应该谨慎使用。 Cat和Mammal通过继承紧密耦合,因此您必须了解类及其交互方式才能理解处理Cat的代码。

答案 3 :(得分:1)

创建的对象是Cat的对象,因此调用时的getName方法位于Cat对象上,因此其名称报告为“morris”。然而,局部变量被定义为哺乳动物,因此除非您明确地将其投射到猫身上,否则无法访问生命。