3

想象一个类Cottage 扩展 Building和代码

Building building = new Building();
Cottage cottage = (Cottage)building;

现在,考虑到 java 继承的性质,不能将Building转换为Cottage是完全有道理的,但是(对我而言)没有意义的是它可以编译。为什么它编译然后抛出运行时ClassCastException

在实际运行程序之前building是对Building对象的引用,这不是很明显吗?

作为一个普遍的问题,我知道我可能会得到一个重复的问题:) 但我找不到为什么它编译问题的答案:)

EDIT2我在这里接受了一个很好的答案(更不用说下面的讨论了:)),但我仍然发现在Java 转换中接受的答案导致运行时错误而不是编译错误是最有趣的......

编辑我编辑了IllegalCastException并放置了正确的ClassCastException

4

3 回答 3

10

那是因为,编译器不知道您的引用Building所指的是什么对象。

因此,在以下情况下,您有一个基类引用,指向子类对象:-

Building building = new Cottage();
Cottage cottage = (Cottage)building;

它会工作得很好。所以,这完全是一个运行时的决定,至于它是否是一个有效的演员表。因此,编译器不会为此抛出错误。

在实际运行程序之前 building 是对 Building 对象的引用,这不是很明显吗?

,绝对不是。被引用的对象的类型直到运行时才知道。永远记住,编译器总是检查引用类型。在运行时检查实际对象类型。

这个概念被称为多态性,您可以使用相同的引用类型来指向各种子类型的对象。你可以谷歌它,并且会得到很多资源来阅读。

于 2013-01-22T21:08:43.170 回答
3

转换的部分功能是它使编译器闭嘴,你是说你比编译器更清楚你要转换的对象是什么。如果演员表不准确,则会出现异常。

也许您希望编译器跟踪事物所指向的对象,并确定引用是否合理。编译器不是那么聪明,很容易被愚弄,请看这个片段:

    int i = 1;
    System.out.println((Number)i);        
    Object o = i;
    System.out.println((String)i); // won't compile (primitive-to-ref-type cast)
    System.out.println((String)o); // compiles (thanks to autoboxing)

编译器只关心防止原语和引用类型之间的转换。

于 2013-01-22T21:10:53.763 回答
2

考虑使用 Building(super class) 引用创建一个 Cottage(Subclass) 对象

Building b= new Cottage();
Cottage c = (Cottage) b;

上面的代码是合法的,因此编译器在运行时不知道引用变量c引用的是什么对象,因此编译器不会抛出错误。

为什么它会编译然后抛出运行时 IllegalCastException?

顺便说一句,当您尝试将超类对象强制转换为子类时,它会抛出ClassCastException ,而不是IllegalCastException

于 2013-01-22T21:10:40.467 回答