超类引用无法在Java中调用子类方法
我对Java中的多态性有一个基本的怀疑。我已经在一个名为AnimalTestDrive.java的文件中编写了下面的代码。据我所知,下面的代码应该特别适用于粗体的行,但不幸的是它不是。你能解释一下为什么,我给出了以下错误:超类引用无法在Java中调用子类方法,java,inheritance,polymorphism,Java,Inheritance,Polymorphism,我对Java中的多态性有一个基本的怀疑。我已经在一个名为AnimalTestDrive.java的文件中编写了下面的代码。据我所知,下面的代码应该特别适用于粗体的行,但不幸的是它不是。你能解释一下为什么,我给出了以下错误: class Dog extends Animal { public void dogMethod() { System.out.println("In Dog method"); } } public class AnimalTestDri
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所知,animal只是一种动物,所以它只能做在animal类中定义的事情。如果你想使用狗的方法,并且你知道你的动物是一只狗,你必须把它扔给一只狗,这样方法才可见
换句话说,变量可用的唯一方法和字段是由其左侧类型定义的方法和字段。你可以说
((狗)动物).dogMethod()
;将动物称为狗,或创建一个新变量Dog animalAsDog=animal编码>并在animalAsDog上调用您的方法。据Java所知,动物只是一种动物,因此它只能做在动物类中定义的事情。如果你想使用狗的方法,并且你知道你的动物是一只狗,你必须把它扔给一只狗,这样方法才可见
换句话说,变量可用的唯一方法和字段是由其左侧类型定义的方法和字段。你可以说((狗)动物).dogMethod()
;将动物称为狗,或创建一个新变量Dog animalAsDog=animal编写>并在animalAsDog上调用您的方法。让我们尝试以编译器的相同方式查看这一行:
animal.dogMethod();
首先,它需要弄清楚动物是什么意思。这很好,也很简单——在当前方法中,它是一个局部变量,所以不需要看得太远
该变量的编译时类型为Animal
。编译器不关心变量在执行时的值是什么-它只使用有关声明类型的信息
因此,这就是它用来查找dogMethod()
在animal
上下文中的含义,即使用类型animal
。首先在Animal
中查找,然后在java.lang.Object
(Animal
的隐式超类)中查找,但这两个类都不包含dogMethod
的声明。在这一点上,编译器不得不放弃一个错误-它找不到方法。该方法在animal
引用的对象的执行时间类型上是否可用并不重要。它必须在编译时绑定它,只使用编译时可用的信息
在执行时所做的唯一决定是使用方法的哪个实现-例如,如果调用animal.toString()
,并且Dog
类具有重写,例如
@Override public String toString() {
return "I'm a dog";
}
然后编译器将从java.lang.Object
中找到toString()
方法,因此它将知道方法调用是有效的-但是由于对象的执行时间类型,将使用Dog
中的实现。让我们尝试以编译器相同的方式查看这一行:
animal.dogMethod();
首先,它需要弄清楚动物是什么意思。这很好,也很简单——在当前方法中,它是一个局部变量,所以不需要看得太远
该变量的编译时类型为Animal
。编译器不关心变量在执行时的值是什么-它只使用有关声明类型的信息
因此,这就是它用来查找dogMethod()
在animal
上下文中的含义,即使用类型animal
。首先在Animal
中查找,然后在java.lang.Object
(Animal
的隐式超类)中查找,但这两个类都不包含dogMethod
的声明。在这一点上,编译器不得不放弃一个错误-它找不到方法。该方法在animal
引用的对象的执行时间类型上是否可用并不重要。它必须在编译时绑定它,只使用编译时可用的信息
在执行时所做的唯一决定是使用方法的哪个实现-例如,如果调用animal.toString()
,并且Dog
类具有重写,例如
@Override public String toString() {
return "I'm a dog";
}
然后编译器将从java.lang.Object
中找到toString()
方法,这样它就知道方法调用是有效的-但是Dog
中的实现将被使用,因为对象的执行时间类型。根据我的说法,下面的代码应该可以工作。您的推理是什么?为什么它要工作?输出是:javac AnimalTestDrive.java AnimalTestDrive.java:24:错误:找不到符号animal.dogMethod();^symbol:method dogMethod()位置:类型为animal 1 errorRight的变量animal,因此它不起作用。为什么你认为它应该?@NikhilSharma:你从哪里得到“然后使用superclassRef.subclassMethod()符号调用子类类型上的方法”部分?你从哪里读到的?@NikhilSharma:这并不是说“然后你只能调用Dog
中声明的方法”,是吗?是的,编译时类型和执行时类型是不同的,但是你已经推断出了更多的东西?为什么它要工作?输出是:javac AnimalTestDrive.java AnimalTestDrive.java:24:错误:找不到符号animal.dogMethod();^symbol:method dogMethod()位置:类型为animal 1 errorRight的变量animal,因此它不起作用。为什么你认为它应该?@NikhilSharma:你从哪里得到“然后使用superclassRef.subclassMethod()符号调用子类类型上的方法”部分?你在哪里读到的?@NikhilShar