Java类转换规则

时间:2018-04-24 20:15:04

标签: java class inheritance casting polymorphism

    public static void main(String[] args) {
       new Redwood().go();
    }
    void go() {
       go2(new Tree(), new Redwood());
       go2((Redwood) new Tree(), new Redwood());
    }
    void go2(Tree t1, Redwood r1) {
       Redwood r2 = (Redwood)t1;
       Tree t2 = (Tree)r1;
    }
}

鉴于Redwood类扩展了Tree,main()方法在Redwood中,而Tree是一个只有默认构造函数的空类;这个考试问题的答案是“当代码试图将树向下转换为红木时,将抛出ClassCastException。”

我想知道为什么抛出异常以及在哪里。根据我的理解,您可以声明Tree t1 = new Redwood(),那么为什么我不能直接将树投射到Redwood?

4 个答案:

答案 0 :(得分:7)

通过使用演员,你基本上告诉编译器"相信我。我是专业人士,我知道我在做什么,我知道虽然你无法保证,但我告诉你这个树变量肯定会是红木。&。 #34;

由于树实际上不是红木(它是一棵树,你可以做Tree tree = new Redwood();而且它是红木)VM会抛出异常运行时因为你违反了那个信任(你告诉编译器一切都会好的而且它不是!)

编译器比仅仅盲目地接受所有内容更聪明一点,如果你尝试在不同的继承层次结构中强制转换对象(例如将红木转换为String),那么编译器会将它抛回给你,因为它知道它永远不会可能会工作。

因为你基本上只是停止编译器的抱怨,所以每次你强制要求你通过在if语句中使用instanceof来检查你是否会导致ClassCastException(或者是那种效果。)

参考http://www.xyzws.com/Javafaq/why-down-casting-throws-classcastexception/125

答案 1 :(得分:2)

每个Redwood都是Tree。这就是Tree t2 = (Tree) r1;有效的原因。

并非每个Tree都是Redwood。这就是Redwood r2 = (Redwood) t1;如果t1Tree而不是Redwood则无效的原因。

更正式的,请参阅JLS §5.1.6

  

六种转换称为缩小参考转换:

     
      
  • 从任何引用类型S到任何引用类型T,前提是S是T(§4.10)的正确超类型。

  •   
  • 一个重要的特殊情况是,从类类型Object到任何其他引用类型(第4.12.4节)存在缩小的引用转换。

  •   
  • 从任何类型C到任何非参数化接口类型K,前提是C不是最终的且不实现K.

  •   
  • 从任何接口类型J到任何非最终的非参数化类型C。

  •   
  • 从任何接口类型J到任何非参数化接口类型K,前提是J不是K的子接口。

  •   
  • 从Cloneable和java.io.Serializable接口类型到任何数组类型T []。

  •   
  • 从任何数组类型SC []到任何数组类型TC [],前提是SC和TC是引用类型,并且从SC到TC有一个缩小的引用转换。

  •   
     

此类转换需要在运行时进行测试,以确定实际参考值是否是新类型的合法值。如果没有,则抛出ClassCastException。

答案 2 :(得分:1)

仅仅因为每棵红木都是树,但每棵树都不是红木。编译器足够聪明,可以保护您的程序做错事。

答案 3 :(得分:0)

Tree类型的变量不包含Tree类型的对象;相反,它将null引用保存到一个保证可用作Tree对象的对象。同样使用Redwood类型的变量。

由于Redwood继承自Tree,因此保证Redwood对象可用作Tree对象,而Tree类型的变量可能会保留对这样一个对象的引用。如果尝试将类型Tree的变量强制转换为Redwood类型的变量,那么如果变量保持null,那么此类强制转换将成功[因为Redwood类型的变量可以保存null],或者如果变量保存对可用作Redwood的对象的引用[因为该类型的变量可以保存任何此类引用],但如果变量成立则会失败对不能用作Redwood [{1}}类型的变量的对象的引用不能保存对此类对象的引用]。

请注意,如果您尝试转换Redwood表达式的结果,系统将表现得好像结果存储在临时变量中,并且应用了强制转换。无论变量是否有任何方式实际上可以保存对可用作new的对象的引用,编译器仍然可能表现得好像该变量可能或可能不包含这样的引用,并且只发现该变量代码执行时没有。