超类引用无法在Java中调用子类方法

时间:2015-02-22 16:27:21

标签: java inheritance polymorphism

我对Java中的多态性有一个基本的疑问。我已将下面的代码写在一个名为AnimalTestDrive.java的文件中。根据我的说法,下面的代码应该特别使用粗体线,但不幸的是它不是。你能解释一下原因吗,我已经给出了以下错误:

class Dog extends Animal {

    public void dogMethod() {
        System.out.println("In Dog method");
    }
}

public class AnimalTestDrive {
    public static void main(String args[]) {
        Dog d = new Dog();
        d.dogMethod();
        d.animalMethod();

        Animal animal = new Animal();
        animal.animalMethod();

        animal = d;
        **animal.dogMethod(); // THIS IS NOT WORKING**

    }
}

2 个答案:

答案 0 :(得分:10)

让我们尝试以与编译器相同的方式查看此行:

animal.dogMethod();

首先,它需要解决animal的含义。这很好也很简单 - 它是当前方法中的局部变量,所以它不需要看得太远。

该变量的编译时类型为Animal。编译器不关心变量的在执行时是什么 - 它只使用有关声明类型的信息。

因此,尝试在dogMethod()的上下文中查找animal意味着什么,即使用类型Animal,这就是它的用途。首先它在Animal中查找,然后在java.lang.ObjectAnimal的隐式超类)中查找 - 但这些类都不包含dogMethod的声明。此时,编译器必须放弃错误 - 它无法找到该方法。该方法在animal引用的值的执行时类型上可用并不重要。它必须在编译时使用编译时可用的信息绑定它。

执行时间做出的唯一决定是使用哪种方法实现 - 例如,如果您调用animal.toString()并且Dog类具有覆盖,例如

@Override public String toString() {
    return "I'm a dog";
}

然后编译器会从toString()找到java.lang.Object方法,因此它会知道方法调用是有效的 - 但Dog中的实现会因为对象的执行时类型而被使用。

答案 1 :(得分:1)

就Java而言,动物只是一种动物,所以它只能做动物类中定义的事物。如果您希望能够使用Dog方法,并且您知道您的动物是狗,则必须将其投射到狗上才能看到该方法。

换句话说,变量可用的唯一方法和字段是由它的左侧类型定义的方法和字段。你可以说((Dog)animal).dogMethod();将动物称为狗,或创建一个新变量Dog animalAsDog = animal;并在animalAsDog上调用您的方法。