多态性错误

Errors In Polymorphism

我对 java 有点陌生,我有一个关于多态性和可能的​​错误的问题。 假设我们有这个:

public interface Animal {
}

public abstract class Cat implements Animal{
}

public abstract class Fish implements Animal {
}

public class Salmon extends Fish{
}

public class Tiger extends Cat{
}

并假设我们有这样的东西:

Animal t1 = new Tiger();
Fish f1 = new Salmon();
Tiger t2= new Tiger();
Salmon s1 = new Salmon();

以下行中的错误是什么(编译时错误、运行时错误或无错误):

Cat c1 = new Cat();
Cat c2 = (Tiger) t1;
Animal a1 = s1;
Animal a2 = new Animal();
Fish f1 = (Fish) t2;
Animal a3 = (Fish) s1;
Animal a4 = (Cat) new Tiger();
Cat c3 = (Cat) new Salmon();

我已经像下面这样回答了,但我觉得我发现没有运行时错误有点奇怪。如果所有这些都是正确的,你能举一个我们有运行时错误的例子吗(在这个多态性概念中)

我的回答:

a  compile error
b  no error
c  no error
d  compile error
e  compile error
f  no error
g  no error
h  compile error

关注“如何在运行时获取异常”部分。

您自己认为 Cat c3 = (Cat) new Salmon(); 是错误的。 显然,编译器已经可以告诉你了。

为什么?因为编译器可以“看到”你创建了一个 Salmon,然后你想把它当作 Cat,这是没有意义的。

你唯一需要“通过”编译器的就是“隐藏”这个事实,比如:

Salmon s1 = new Salmon();
Animal a3 = (Fish) s1;
Cat c3 = (Cat) a3;

一旦你介绍 a3,你就可以“隐藏”s1 实际上是鲑鱼的事实。

当然:即使在我的示例中,更聪明的编译器也可以理解a3必须是鲑鱼,可以成为一只猫。但是 java 在这里玩得“简单而保守”。编译器只识别最基本的转换违规,无论好坏,java 语言都会忽略许多 也可以 在编译时检测到的情况。这使得编译器的实现变得更加容易,缺点是您的代码在运行时更容易遇到此类异常。

你的答案都是正确的。较新的编译器应该会发现在您的示例中强制转换失败的情况。只有在编译器将无法跟踪实际类型的情况下才会抛出运行时异常,因为类型是向下转换的:

public Cat catterize(Animal a) {
    return (Cat) a; // this line should yield an unsafe typecast warning!
}

...

Salmon salmon = new Salmon();
Cat cat = catterize(salmon); // This is compiletime legal, but will ultimately throw a ClassCastException.

由于Java只支持classes的单继承,它可以验证classes之间的转换是否潜在有效,因为在转换时,class之一]es 必须是另一个的祖先。你可以做向上转换,例如TigerCat,或者你可以做向下转换,例如CatTiger.

我忽略了愚蠢的身份转换,例如TigerTiger,当然也是允许的。

您不能将 class 转换为与它“不相关”的另一个 class。

编译器无法验证关于接口的相同内容,因为允许多重继承,这意味着在编译时,始终可以将 class 或接口转换为接口,并将接口转换为class 或其他接口也总是可能的。转换只能在运行时验证。

由于您没有两个 class 继承自同一基础 class,因此您无法为 class 之间的转换设置运行时错误。编译器总是会捕获错误。

由于您只有一个接口,并且所有 classes 都实现了该接口,因此您无法设置运行时错误以将 转换为 接口。

这意味着要设置运行时错误,您需要将转换为一个class接口真实对象不兼容,例如从 Animal t1(真实对象 Tiger)转换为 SalmonFish 就可以了:

Salmon s2 = (Salmon) t1; // ClassCastException: class Tiger cannot be cast to class Salmon