我无法解释为什么对多态对象的方法调用无法编译
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
时,它会说,“好的,它可以容纳任何类型的动物。”而且它只允许您调用对所有种动物有效的方法。
我知道下面问题的答案是陈述 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
时,它会说,“好的,它可以容纳任何类型的动物。”而且它只允许您调用对所有种动物有效的方法。