【问题标题】:Errors In Polymorphism多态性错误
【发布时间】:2021-05-02 04:40:04
【问题描述】:

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

【问题讨论】:

  • 好吧,您只需运行该代码即可测试您的答案。你不需要任何其他人。
  • 我运行代码,这就是我得到的答案。我对如何发生运行时错误感到困惑?

标签: java error-handling polymorphism runtime-error


【解决方案1】:

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

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

为什么?因为编译器可以“看到”您创建了一个 Salmon,然后您想将其视为 Cat,这是没有意义的。

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

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

只要您介绍了a3,您就可以“隐藏”s1 实际上是三文鱼这一事实。

当然:即使在我的示例中,更智能的编译器也可以理解a3 必须是鲑鱼,不能是猫。但是java在这里玩它“简单而保守”。编译器只识别最基本的强制转换违规,无论好坏,java 语言都会忽略许多在编译时可能被检测到的情况。这使得编译器的实现更容易,权衡是您的代码在运行时更容易受到此类异常的影响。

【讨论】:

    【解决方案2】:

    由于Java只支持类的单一继承,它可以验证类之间的转换是否潜在有效,因为在转换时,其中一个类必须是另一个类的祖先。您可以进行向上转换,例如TigerCat,或者您可以进行向下转换,例如CatTiger

    我忽略了愚蠢的身份演员,例如TigerTiger,当然也可以。

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

    编译器无法对接口进行验证,因为允许多重继承,这意味着在编译时,始终可以将类或接口转换为接口,并且将接口转换为类或另一个接口是也总是可能的。转换只能在运行时验证。

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

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

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

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

    【讨论】:

      【解决方案3】:

      你的答案都是正确的。较新的编译器应该找到在您的示例中强制转换失败的情况。运行时异常只会在编译器丢失实际​​类型的情况下抛出,因为类型是向下转换的:

      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.
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-02-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-04
        • 1970-01-01
        • 2017-01-01
        • 1970-01-01
        相关资源
        最近更新 更多