我无法解释为什么对多态对象的方法调用无法编译

I can't explain why a method call on a polymorphic object will not compile

我知道下面问题的答案是陈述 1 和陈述 3。但是我无法解释为什么陈述 2 不起作用。有人可以启发我吗?谢谢

考虑以下 class 定义。

public class Animal
{
    public void eat()
    { /* implementation not shown */ }
    // constructors and other methods not shown
}

public class Tiger extends Animal
{
    public void roar()
    { /* implementation not shown */ }
    // constructors and other methods not shown
}

假设以下声明出现在客户端class。

 Animal a = new Tiger();

以下哪些语句可以正确编译?

我。 a.eat();

二. a.roar();

三。 ((虎)a).咆哮();

我假设将 'a' 实例化为新的 Tiger() 将允许 'a' 访问 roar() 方法。但我显然错了。我想我没有很好地理解问题的多态性。

因为 'a' 被引用为动物。就代码而言,它只能直接访问 Animal 定义的方法。你的第三行是有效的,因为你明确地将它转换为 Tiger,从而改变上下文并允许它访问 Tiger 方法,只要没有 ClassCastException。

这样的 class 应该设计的方式是让 Animal 成为一个抽象的 class 然后给它一个抽象的“说话”方法,比如:

 public abstract class Animal {
     public abstract void speak();
 }

然后在你的 Tiger class

public class Tiger extends Animal {
    public void speak() {
       System.out.println("Roar.");
    }
}

那你可以打电话

Animal a = new Tiger();
a.speak();

那你也可以养狗

public class Dog extends Animal {
    public void speak() {
       System.out.println("Woof.");
    }
}

Animal a = new Dog();
a.speak();

SO 上有很多这样的问题,答案总是 Java 认为静态类型是 Animal 所以调用 Tiger 的方法不会编译, 但我认为多说一点 为什么 .

可能会有用

考虑:

Animal a = new Tiger();
a.roar();

很容易看出,虽然 a 被声明为 Animal,但它只能在调用 [=17= 时引用 Tiger ].但考虑一个更复杂的例子:

Animal a = new Tiger();
// . . .
if (zoo.getType() == ZooType.TROPICAL) {
    a = new Toucan();
}
for (Condition c : getMeteorologicalConditions()) {
    // . . .
    if (season == Seasons.WINTER) {
        a = new Penguin();
    }
    // . . .
}
// . . .
a.roar();

在这里打电话给roar()安全吗?什么时候安全?编译器能否在编译时静态地证明 a 将始终是 Tiger?也许可以以某种方式表明,永远不会为热带动物园或冬天调用此代码(至少在有任何适用的气象条件的情况下;否则,循环将执行零次,而冬天则无关紧要)。但是你能想象证明这一点的复杂性吗?

编译器甚至不尝试。当你告诉它 a 是一个 Animal 时,它会说,“好的,它可以容纳任何类型的动物。”而且它只允许您调用对所有种动物有效的方法。