我想知道是否有人能告诉我铸造是如何工作的?我理解何时我应该这样做,但不是真的如何运作。在原始数据类型上我部分理解但是当涉及到构建对象时,我不明白它是如何工作的。
如何突然将类型为Object的对象强制转换为MyType
(仅作为示例),然后获取所有方法?
答案 0 :(得分:168)
使用Java进行投射并不神奇,而是告诉编译器类型A的对象实际上是更具体的类型B,因此可以访问B上的所有其他方法。你在执行转换时没有执行任何魔法或转换,你实际上是在告诉编译器“相信我,我知道我在做什么,我可以保证你在这一行的这个对象实际上是一个< Insert这里的演员类型>。“例如:
Object o = "str";
String str = (String)o;
以上是好的,不是魔法,一切都很好。存储在o中的对象实际上是一个字符串,因此我们可以毫无问题地转换为字符串。
有两种方法可能出错。首先,如果你在完全不同的继承层次结构中的两种类型之间进行转换,那么编译器就会知道你是愚蠢的并阻止你:
String o = "str";
Integer str = (Integer)o; //Compilation fails here
其次,如果它们在同一个层次结构中但仍然是无效的强制转换,那么将在运行时抛出ClassCastException
:
Number o = new Integer(5);
Double n = (Double)o; //ClassCastException thrown here
这实际上意味着您违反了编译器的信任。你告诉它你可以保证对象属于特定类型,但事实并非如此。
为什么需要施法?好吧,从一开始就只需要从更通用的类型到更具体的类型。例如,Integer
继承自Number
,因此如果您想将Integer
存储为Number
,那就没问题(因为所有整数都是数字。)但是,如果你想要反过来你需要一个演员 - 不是所有的数字都是整数(以及整数我们有Double
,Float
,Byte
,Long
等。 )即使你的项目中只有一个子类或JDK,有人可以很容易地创建另一个并分发它,所以即使你认为它是一个明显的选择,你也无法保证!
关于使用铸造,你仍然会在某些库中看到它的需要。在Java-5之前,它在集合和各种其他类中被大量使用,因为所有集合都在处理添加对象,然后将结果转换回集合。然而,随着仿制药的出现,大部分用于铸造的东西已经消失 - 它已经被泛型替代,它提供了更安全的替代方案,没有ClassCastExceptions的可能性(事实上如果你干净地使用泛型并且它没有警告编译,你可以保证你永远不会得到ClassCastException。)
答案 1 :(得分:7)
实际上,施法并不总是有效。如果该对象不是instanceof
您正在将其投射到的类,则会在运行时获得ClassCastException
。
答案 2 :(得分:5)
假设您想要将String
转换为File
(是的,它没有任何意义),您不能直接转换它,因为File
类不是孩子而不是String
类的父级(以及编译器抱怨)。
但是您可以将String
转换为Object
,因为String
是Object
(Object
是父级)。然后,您可以将此对象转换为File
,因为文件是Object
。
因此,在编译时,从打字的角度来看,所有操作都是“合法的”,但这并不意味着它将在运行时运行!
File f = (File)(Object) "Stupid cast";
即使没有意义,编译器也允许这样做,但是在运行时它会因此异常而崩溃:
Exception in thread "main" java.lang.ClassCastException:
java.lang.String cannot be cast to java.io.File
答案 3 :(得分:2)
投射引用只有在instanceof
类型的情况下才有效。您无法投射随机参考。此外,您需要在Casting Objects
.
e.g。
String string = "String";
Object object = string; // Perfectly fine since String is an Object
String newString = (String)object; // This only works because the `reference` object is pointing to a valid String object.
答案 4 :(得分:0)
正确的方法是这样:
Integer i = Integer.cast(obj);
方法cast()
是编译时强制转换的一种更安全的选择。