Java Class.cast()与cast操作符
在我的C ++日子里教过关于C风格演员操作符的邪恶之后,我很高兴地首先发现,在Java 5中, java.lang.Class
已经获得了一个cast
方法。
我想最后我们有一个OO的方式处理铸造。
原来, Class.cast
与C ++中的static_cast
。 这更像reinterpret_cast
。 它不会在预期的地方产生编译错误,而是会延迟到运行时。 这是一个简单的testing用例来演示不同的行为。
package test; import static org.junit.Assert.assertTrue; import org.junit.Test; public class TestCast { static final class Foo { } static class Bar { } static final class BarSubclass extends Bar { } @Test public void test ( ) { final Foo foo = new Foo( ); final Bar bar = new Bar( ); final BarSubclass bar_subclass = new BarSubclass( ); { final Bar bar_ref = bar; } { // Compilation error final Bar bar_ref = foo; } { // Compilation error final Bar bar_ref = (Bar) foo; } try { // !!! Compiles fine, runtime exception Bar.class.cast( foo ); } catch ( final ClassCastException ex ) { assertTrue( true ); } { final Bar bar_ref = bar_subclass; } try { // Compiles fine, runtime exception, equivalent of C++ dynamic_cast final BarSubclass bar_subclass_ref = (BarSubclass) bar; } catch ( final ClassCastException ex ) { assertTrue( true ); } } }
所以,这是我的问题。
-
Class.cast()
应该被放逐到generics土地? 在那里有相当多的合法用途。 - 当使用
Class.cast()
时,编译器是否会产生编译错误,编译时Class.cast()
非法的条件? - Java应该提供一个类似于C ++的语言结构吗?
我只使用Class.cast(Object)
来避免在“generics土地”中的警告。 我经常看到像这样做的方法:
@SuppressWarnings("unchecked") <T> T doSomething() { Object o; // snip return (T) o; }
通常最好将其replace为:
<T> T doSomething(Class<T> cls) { Object o; // snip return cls.cast(o); }
这是我见过的Class.cast(Object)
的唯一用例。
关于编译器警告:我怀疑Class.cast(Object)
对于编译器来说并不特别。 当静态使用时(如Foo.class.cast(o)
而不是cls.cast(o)
),它可以被优化,但是我从来没有见过任何人使用它 – 这使得在编译器中构build这种优化的工作有些毫无价值。
首先,你几乎不打算做任何演员,所以你应该尽可能地限制它! 您将失去Java编译时强typesfunction的好处。
在任何情况下, Class.cast()
都应该主要在通过reflection检索Class
标记时使用。 写作更加地道
MyObject myObject = (MyObject) object
而不是
MyObject myObject = MyObject.class.cast(object)
编辑:在编译时的错误
总而言之,Java只在运行时执行强制检查。 然而,如果编译器可以certificate这样的转换永远不会成功(例如,将一个类转换为另一个不是超类的类,并将最终的类types转换为不在其types层次中的类/接口),则编译器可以发出错误。 在这里,因为Foo
和Bar
是不在其他层次结构中的类,所以转换不会成功。
尝试翻译语言之间的结构和概念往往是有问题的,而且往往是误导。 铸造也不例外。 特别是因为Java是一种dynamic语言,C ++有所不同。
所有在Java中的转换,不pipe你怎么做,都是在运行时完成的。 types信息在运行时保存。 C + +是多一点混合。 你可以在C ++中将一个结构体转换为另一个结构体,这只是对表示这些结构体的字节的重新解释。 Java不能这样工作。
Java和C ++中的generics也大不相同。 不要过分担心自己如何在Java中使用C ++的东西。 你需要学习如何用Java的方式做事情。
Java代码中很less使用Class.cast()
。 如果通常使用只在运行时才知道的types(即通过它们各自的Class
对象和一些types参数)。 这只是在使用generics的代码中非常有用(这也是之前没有介绍的原因)。
它与reinterpret_cast
不是类似的,因为它不会让你在运行时破坏types系统,而不是像普通的types那样(也就是说,你可以“破坏”genericstypes参数,但不能“破坏”真正的types) 。
C风格的演员操作的弊端通常不适用于Java。 看起来像C风格转换的Java代码与Java中引用types(请记住:Java具有运行时types信息)的dynamic_cast<>()
最为相似。
一般来说,比较C ++types的转换操作符和Java转换是相当困难的,因为在Java中,只能转换引用,而不会发生对象转换(只能使用这种语法转换原始值)。
C ++和Java是不同的语言。
Java C风格的转换运算符比C / C ++版本更受限制。 有效的Java转换就像C ++的dynamic_cast,如果你拥有的对象不能被转换到新的类中,你将得到一个运行时(或者如果代码中有足够的信息一个编译时)exception。 因此,不使用Ctypes转换的C ++思想在Java中不是一个好主意