【问题标题】:Superclass reference not able to call subclass method in Java超类引用无法在 Java 中调用子类方法
【发布时间】:2015-04-23 23:23:48
【问题描述】:

我对 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**

    }
}

【问题讨论】:

  • 根据我的说法,下面的代码应该可以工作你的理由是什么?为什么它应该起作用?
  • 输出为:javac AnimalTestDrive.java AnimalTestDrive.java:24: error: cannot find symbol animal.dogMethod(); ^ 符号:方法 dogMethod() 位置:变量 Animal 类型 Animal 1 错误
  • 对,所以它不起作用。为什么你认为应该这样做?
  • @NikhilSharma:你从哪里得到“然后使用符号 as superclassRef.subclassMethod() 调用 subclassType 上的方法”部分?你在哪里读到的?
  • @NikhilSharma:这并不是说“然后你可以调用仅在Dog 中声明的方法”,是吗?是的,编译时类型和执行时类型可以不同 - 但您推断的远不止这些。

标签: java inheritance polymorphism


【解决方案1】:

让我们尝试以编译器的方式查看这一行:

animal.dogMethod();

首先,它需要弄清楚animal 的含义。这很好也很简单——它是当前方法中的一个局部变量,所以不需要看太远。

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

所以,这就是它用来尝试在animal 的上下文中查找dogMethod() 的含义,即类型为Animal。首先它在Animal 中查找,然后在java.lang.ObjectAnimal 的隐式超类)中查找——但这些类都不包含dogMethod 的声明。到那时,编译器不得不放弃一个错误——它找不到方法。该方法在animal 所引用的值的对象的 execution-time 类型上可用并不重要。它必须在编译时绑定它,只使用编译时可用的信息。

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

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

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

【讨论】:

  • 关于运行时多态性以及这里的超类类型引用是animal可以引用子类类型对象的原理,这里是Dog。所以,我认为我的代码应该可以工作
  • @NikhilSharma 什么运行时?这在编译时编译失败。
  • @NikhilSharma 多态性将覆盖 animalMethod
  • @NikhilSharma 是的,它可以指代你的狗,但这里的关键思想是你指的是它作为动物,并且只能在狗上执行Animal 上可用的方法。
  • @NikhilSharma:您的代码肯定肯定不应该工作。问题不在于编译器或超类类型引用可以引用子类类型对象的原则 - 您期望可以通过编译时类型的表达式调用仅在子类中声明的方法是超类。
【解决方案2】:

据 Java 所知,animal 只是一种动物,所以它只能做在 Animal 类中定义的事情。如果您希望能够使用 Dog 方法,并且您知道您的动物是 Dog,则必须将其强制转换为 Dog 才能使该方法可见。

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

【讨论】:

  • 在将animal 分配给animalAsDog 时不要忘记转换。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-24
  • 2020-07-15
  • 1970-01-01
  • 2019-05-19
相关资源
最近更新 更多