为什么编译得很好(后面有明显的运行时异常)

时间:2015-03-02 03:24:59

标签: java

我有一个超类动物和两个子类:猫和狗。 Dog类有一个独有的新方法叫做playFetch()。

现在,我这样做:

Animal G = new Cat("Tom");
((Dog) G).playFetch();

那么,编译器在编译它之前究竟是怎么想的,没有任何错误。是否认为......"好的,Trent是将动物对象引用类型转换为Dog对象引用的参考,我认为没有任何错误,因为Dog也是动物和狗的方法是playFetch()&#34 ; ?

在运行期间,嗯......我们知道会发生什么。请说服我为什么编译器没有抱怨。或者我的论点是否正确?

3 个答案:

答案 0 :(得分:2)

Casting总是强制进行强制转换,并且由程序员正确使用它。也许你正试图为了单元测试而生成一个ClassCastException(“Cats永远不应该扩展Dogs”),或者有编译器不理解的其他计划。因此,当您使用告诉编译器退避的功能时,编译器会退出,并且转换是这些功能之一。

(这也解释了为什么规范允许编译器这样做。)

答案 1 :(得分:1)

编译器认为它应该符合Java语言规范,包括15.16. Cast Expressions

  

如果操作数的编译时类型可能是编译时错误   永远不会被强制转换为由强制转换运算符指定的类型   铸造转换规则(§5.5)。

     

否则,在运行时,转换操作数值(如有必要)   通过将转换转换为强制转换操作符指定的类型。

规范不要求进行数据流分析,以确定特定强制转换的操作数始终是不兼容的子类型。可编译Java程序的定义应该独立于编译器的选择。

如果您希望编译器知道G总是引用Cat,请将其声明为Cat类型,而不是Animal类型。

答案 2 :(得分:0)

The cast is legal by the JLS,因为DogAnimal。具体来说,这条规则就是强制执行的目标:

  

如果T是类类型,则为| S | &lt ;: | T |,或| T | <:| S |。否则,发生编译时错误。

请注意,它确实说编译时。结果ClassCastException在运行时发生,特别是当您要转换的目标类无效时。

通常,您可以 up 继承链(即DogAnimal,而Dog是{{1} }}),但你不能向下(没有任何说法ObjectAnimal,或者DogObject )。