超类引用无法在 Java 中调用子类方法
Superclass reference not able to call subclass method in Java
我对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**
}
}
据Java所知,动物就是动物,所以它只能做你的动物class中定义的事情。如果您希望能够使用 Dog 方法,并且您知道您的动物是 Dog,则必须将其转换为 Dog 才能使该方法可见。
换句话说,变量唯一可用的方法和字段是由其左侧类型定义的方法和字段。你可以说 ((Dog)animal).dogMethod()
;将动物称为狗,或创建一个新变量 Dog animalAsDog = animal;
并在 animalAsDog 上调用您的方法。
让我们尝试以与编译器相同的方式查看这一行:
animal.dogMethod();
首先,它需要弄清楚animal
是什么意思。这很好也很简单 - 它是当前方法中的一个局部变量,所以不需要看得太远。
该变量的编译时类型是 Animal
。编译器不关心变量的 value 在执行时是什么——它只使用关于声明类型的信息。
所以,这就是它用来尝试在 animal
的上下文中查找 dogMethod()
的含义,即类型 Animal
。首先它在 Animal
中查找,然后在 java.lang.Object
中查找(Animal
的隐式 superclass)——但是这些 classes 都不包含 [= 的声明20=]。那时,编译器不得不报错放弃——它找不到方法。该方法在 execution-time 类型的对象(animal
所指的值)上可用并不重要。它必须在编译时绑定它,仅使用编译时可用的信息。
在 执行 时做出的唯一决定是使用哪个方法的实现 - 例如,如果您调用 animal.toString()
并且 Dog
class 有一个覆盖,例如
@Override public String toString() {
return "I'm a dog";
}
然后编译器将从 java.lang.Object
中找到 toString()
方法,因此它会知道该方法调用是有效的 - 但 实现 [由于对象的执行时类型,将使用 =23=]。
我对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**
}
}
据Java所知,动物就是动物,所以它只能做你的动物class中定义的事情。如果您希望能够使用 Dog 方法,并且您知道您的动物是 Dog,则必须将其转换为 Dog 才能使该方法可见。
换句话说,变量唯一可用的方法和字段是由其左侧类型定义的方法和字段。你可以说 ((Dog)animal).dogMethod()
;将动物称为狗,或创建一个新变量 Dog animalAsDog = animal;
并在 animalAsDog 上调用您的方法。
让我们尝试以与编译器相同的方式查看这一行:
animal.dogMethod();
首先,它需要弄清楚animal
是什么意思。这很好也很简单 - 它是当前方法中的一个局部变量,所以不需要看得太远。
该变量的编译时类型是 Animal
。编译器不关心变量的 value 在执行时是什么——它只使用关于声明类型的信息。
所以,这就是它用来尝试在 animal
的上下文中查找 dogMethod()
的含义,即类型 Animal
。首先它在 Animal
中查找,然后在 java.lang.Object
中查找(Animal
的隐式 superclass)——但是这些 classes 都不包含 [= 的声明20=]。那时,编译器不得不报错放弃——它找不到方法。该方法在 execution-time 类型的对象(animal
所指的值)上可用并不重要。它必须在编译时绑定它,仅使用编译时可用的信息。
在 执行 时做出的唯一决定是使用哪个方法的实现 - 例如,如果您调用 animal.toString()
并且 Dog
class 有一个覆盖,例如
@Override public String toString() {
return "I'm a dog";
}
然后编译器将从 java.lang.Object
中找到 toString()
方法,因此它会知道该方法调用是有效的 - 但 实现 [由于对象的执行时类型,将使用 =23=]。