我对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**
}
}
答案 0 :(得分:10)
让我们尝试以与编译器相同的方式查看此行:
animal.dogMethod();
首先,它需要解决animal
的含义。这很好也很简单 - 它是当前方法中的局部变量,所以它不需要看得太远。
该变量的编译时类型为Animal
。编译器不关心变量的值在执行时是什么 - 它只使用有关声明类型的信息。
因此,尝试在dogMethod()
的上下文中查找animal
意味着什么,即使用类型Animal
,这就是它的用途。首先它在Animal
中查找,然后在java.lang.Object
(Animal
的隐式超类)中查找 - 但这些类都不包含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上调用您的方法。