超类引用无法在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

我对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所知,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