简体   繁体   English

Java类转换规则

[英]Java Class Casting Rules

    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;
    }
}

Given the class Redwood extends Tree, the main() method is in Redwood and Tree is an empty class with only a default constructor; 给定Redwood扩展Tree类,则main()方法位于Redwood中,并且Tree是一个空类,仅具有默认构造函数; the answer to this exam question is "A ClassCastException will be thrown when the code attempts to downcast a Tree to a Redwood." 该考试问题的答案是“当代码尝试将Tree转换为Redwood时,将引发ClassCastException。”

I want to know why the exception is thrown and where. 我想知道为什么会引发异常以及在何处。 From my understanding you can declare Tree t1 = new Redwood() so why can't I cast a Tree to a Redwood directly? 根据我的理解,您可以声明Tree t1 = new Redwood(),为什么我不能直接将Tree投射到Redwood?

By using a cast you're essentially telling the compiler "trust me. I'm a professional, I know what I'm doing and I know that although you can't guarantee it, I'm telling you that this tree variable is definitely going to be a redwood." 通过使用强制转换,您实际上是在告诉编译器“相信我。我是专业人士,我知道我在做什么,我知道尽管不能保证,但是我告诉你这个树变量是肯定会成为红杉。”

Since the tree isn't actually a redwood(it's an tree, you could do Tree tree = new Redwood(); and it'd be a redwood) the VM throws an exception at runtime because you've violated that trust (you told the compiler everything would be ok and it's not!) 由于树实际上不是一棵红杉(它是一棵树,您可以执行Tree tree = new Redwood();它将是一棵红杉),因为您违反了这种信任,VM在运行时抛出异常(您告诉编译器一切都会好起来的,不是!)

The compiler is a bit smarter than just blindly accepting everything, if you try and cast objects in different inheritence hierarchies (cast a redwood to a String for example) then the compiler will throw it back at you because it knows that could never possibly work. 编译器比盲目地接受所有内容要聪明一些,如果您尝试将对象强制转换为不同的继承层次结构(例如,将红木投射到String中),则编译器会将其扔给您,因为它知道这种方法永远无法工作。

Because you're essentially just stopping the compiler from complaining, every time you cast it's important to check that you won't cause a ClassCastException by using instanceof in an if statement (or something to that effect.) 因为您实际上只是在停止编译器的抱怨,所以每次转换时,都必须在if语句中使用instanceof(或有此作用的东西)来检查是否不会导致ClassCastException。

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

Every Redwood is a Tree . 每个Redwood都是一Tree This is why Tree t2 = (Tree) r1; 这就是为什么Tree t2 = (Tree) r1; works. 作品。

Not every Tree is a Redwood . 并非每Tree都是Redwood This is why Redwood r2 = (Redwood) t1; 这就是为什么Redwood r2 = (Redwood) t1; will not work if t1 is a Tree but not Redwood . 如果t1Tree但不是Redwood将不起作用。

More formally, see JLS §5.1.6 : 更正式地,请参见JLS§5.1.6

Six kinds of conversions are called the narrowing reference conversions: 六种转换称为收窄参考转换:

  • From any reference type S to any reference type T, provided that S is a proper supertype of T (§4.10). 从任何引用类型S到任何引用类型T,前提是S是T的适当超类型(第4.10节)。

  • An important special case is that there is a narrowing reference conversion from the class type Object to any other reference type (§4.12.4). 一个重要的特殊情况是,从类类型Object到任何其他引用类型的引用转换范围越来越窄(第4.12.4节)。

  • From any class type C to any non-parameterized interface type K, provided that C is not final and does not implement K. 从任何类类型C到任何非参数化接口类型K,只要C不是最终的并且不实现K。

  • From any interface type J to any non-parameterized class type C that is not final. 从任何接口类型J到非最终的任何非参数化类类型C。

  • From any interface type J to any non-parameterized interface type K, provided that J is not a subinterface of K. 如果J不是K的子接口,则从任何接口类型J到任何非参数化接口类型K。

  • From the interface types Cloneable and java.io.Serializable to any array type T[]. 从接口类型Cloneable和java.io.Serializable到任何数组类型T []。

  • From any array type SC[] to any array type TC[], provided that SC and TC are reference types and there is a narrowing reference conversion from SC to TC. 从任何数组类型SC []到任何数组类型TC [],条件是SC和TC是引用类型,并且从SC到TC的引用转换范围越来越窄。

Such conversions require a test at run time to find out whether the actual reference value is a legitimate value of the new type. 此类转换需要在运行时进行测试,以查明实际参考值是否为新类型的合法值。 If not, then a ClassCastException is thrown. 如果不是,则抛出ClassCastException。

Simply because Every Redwood is a Tree but Every Tree is not Redwood. 仅仅是因为每棵红木都是一棵树,但每棵树都不是红木。 The Compiler is smart enough to protect your program to do wrong things. 编译器足够聪明,可以保护您的程序执行错误的操作。

A variable of type Tree does not hold an object of type Tree ; 类型的变量Tree不成立类型的对象Tree ; instead, it holds either null or a reference to an object which is guaranteed to be usable as a Tree object. 相反,它持有null或对对象的引用 ,该对象保证可以用作Tree对象。 Likewise with a variable of type Redwood . 同样,类型为Redwood的变量。

Because Redwood inherits from Tree , a Redwood object is guaranteed to be usable as a Tree object, and a variable of type Tree might hold a reference to such an object. 因为RedwoodTree继承,所以保证Redwood对象可用作Tree对象,并且Tree类型的变量可能包含对该对象的引用。 If one tries to cast a variable of type Tree to a variable of type Redwood , such a cast will succeed if the variable holds null [since a variable of type Redwood can hold null ], or if the variable holds a reference to an object which is usable as a Redwood [since a variable of that type can hold any such reference], but will fail if the variable holds a reference to an object which is not usable as a Redwood [variables of type Redwood cannot hold references to such objects]. 如果尝试将类型为Tree的变量转换为Redwood类型的变量,则如果该变量持有null [因为Redwood类型的变量可以持有null ],或者该变量持有对该对象的引用,则此类转换将成功可用作Redwood [因为该类型的变量可以保存任何此类引用],但如果该变量持有对不可用作Redwood的对象的引用,则将失败[ Redwood类型的变量无法保存对此类对象的引用] 。

Note that if you try to cast the result of a new expression, the system will behave as though that result was stored into a temporary variable, and the cast was applied to that. 请注意,如果您尝试强制转换new表达式的结果,系统将表现为该结果已存储到临时变量中,并且强制转换已应用于该临时变量。 Whether or not there is any way the variable could actually hold a reference to an object which is usable as a Redwood , the compiler may still behave as though the variable might or might not hold such a reference, and only discover that it doesn't when the code is executed. 不管变量是否有任何实际方式可以保存对可用作Redwood的对象的引用,编译器仍可能会表现出该变量可能或可能不包含此类引用的行为,并且只会发现它没有代码执行时。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM