为什么这种类型的继承有效?

时间:2015-05-16 09:35:52

标签: java inheritance

首先我定义了超类:

public class Living {
    double energy;

    Living(double energy) {
        this.energy = energy;
    }
}

然后我定义了子类:

public class Person extends Living {
    String name;

    Person(double energy, String name) {
        super(energy);  
        this.name = name;
    }

    public String getName() {
        return this.name;
    }

    public String toString() {
        String s = this.getName() + " " +  this.energy;
        return s;
    }

}

现在,如果我这样做:

Living creature = new Person(15.2, "Joe");

我将使用Living构造函数创建一个Person类型的生物。这是允许的,因为PersonLiving的特化。

但是我仍然无法通过点运算符访问Person类的方法 - 例如creature.getName(),因为生物被声明为Living类型而不是Person

System.out.println(creature.getName()); //not possible

但如果我这样做:

System.out.println(creature.toString());

我得到了

Joe 15.2

因此,不是toString()类的Living方法(不覆盖),而是调用toString()类的Person方法。我无法理解为什么会这样。

我在开头声明生物应该是Living类型,尽管我使用Person构造函数。如果生物没有name属性且其toString()方法未被覆盖,我该如何获得上述输出?

5 个答案:

答案 0 :(得分:3)

该对象确实是Person的一个实例,因此具有所有Person方法。但是,引用属于Living类型。编译器不知道它的运行时类型,只允许你访问它已经知道的方法。将是可用的 - 即Living类型的方法。

然而,可以强制将此变量视为Person,但显式转换:

System.out.println(((Person) creature).getName())

答案 1 :(得分:2)

对于每个对象,都有一个表(虚拟表),用于保存有关为此对象定义的方法的信息。

如果在给定对象中重写了父方法,则此表将存储重写方法的地址,即使该对象被引用为父类之一。每次调用方法时,此表用于查找如何访问该方法。

因此,在您的情况下,它将使用重新定义的方法toString,因为它已替换父方法。

答案 2 :(得分:1)

LivingObject中声明(您的所有类都继承了该数据),这就是为什么您可以调用它而不在类equals()中重写(有些适用于hashCode()toString()等方法。

请注意,如果您要在Living的其他子类上调用Animal,例如toString()明确覆盖{{1} }},您将从toString()获得默认的Object结果。

public class Animal extends Living {
    String name;

    Person(double energy, String name) {
        super(energy);  
        this.name = name;
    }

    public String getName() {
        return this.name;
    }

    // no toString override here

}

toString()上致电Animal

Living animal = new Animal(100, "Fido");
System.out.println(animal.toString()); // something like your.package.Animal@757dbeaf

答案 3 :(得分:1)

这是面向对象编程的主要特征之一。

执行Living creature = new Person(15.2, "Joe");时,您定义的变量类型为Living,但如您所述,专门为Person。这意味着它不会拥有Person方法,只有它的专业化!

因此,例如,如果Living有方法

public String getName() {
    return "foobar";
}

并且您致电creature.getName(),回报不是"foobar",而是"Joe"。因为'专业化'将调用该方法,而不是super方法本身。

但是,只有专业的方法才能实现。可以被称为:那些特定于Person或任何其他子类的人都可以。

答案 4 :(得分:0)

对象的类型为Person,但类型为Living时的引用。由于Living没有声明getName()方法,因此当您尝试调用它时会出现编译错误。

toString()方法实际上是在Object中声明的,LivingtoString()隐式父级,因此Person 是< / em>声明。由于对象属于toString()类型,并且它会覆盖<a href="Your Link Here" target="_blank" onclick="window.open('Your Link Here');">Click Here</a> ,因此它是被调用的对象。