为什么我要使用java.lang.Class.cast

可能重复:
什么时候应该使用类的java 5方法?

我最近偶然发现了一段像这样的代码:

Object o = .. ; Foo foo = Foo.class.cast(o); 

我实际上甚至都不知道java.lang.Class有一个强制转换方法,所以我查看了文档,从我收集的内容中,这只是对类对象所代表的类进行强制转换。 所以上面的代码大致相当于

 Object o = ..; Foo foo = (Foo)o; 

所以我想知道,为什么我会想要使用强制转换方法而不是简单地做一个“旧方法”。 有没有一个很好的例子,使用cast方法比简单的转换更有益?

从Java Class.cast()到cast运算符

我只使用Class.cast(Object)来避免“generics土地”中的警告。 我经常看到方法做这样的事情:

 @SuppressWarnings("unchecked")  T doSomething() { Object o; // snip return (T) o; } 

通常最好替换它

  T doSomething(Class cls) { Object o; // snip return cls.cast(o); } 

这是我遇到的Class.cast(Object)的唯一用例。

我不认为它经常与你所展示的完全一致。 我见过的最常见的用途是使用generics的人试图做的相当于:

 public static  T castToNumber(Object o) { return (T)o; } 

由于类型擦除,这并没有真正做任何有用的事情。

虽然这是有效的,并且是类型安全的(模数ClassCastExceptions ):

 public static  T castToNumber(Object o, Class clazz) { return clazz.cast(o); } 

编辑 :几个使用谷歌番石榴的例子:

  • MutableClassToInstanceMap
  • 在Throwables#propagateIfInstanceOf中可爱使用,用于类型安全通用抛出规范

在Java中,通常有不止一种方法可以对猫进行皮肤处理。 在您拥有框架代码的情况下,此类function可能很有用。 想象一个方法,它接受一个Class对象实例和一个Object实例,并返回Object case作为类:

 public static void doSomething(Class whatToCastAs,Object o) { SomeBaseClass castObj = whatToCastAs.cast(o); castObj.doSomething(); } 

通常,使用更简单的铸造,除非它不够。

在某些情况下,您只知道在运行时将对象强制转换为的类型,并且必须使用强制转换方法。

绝对没有理由写Foo.class.cast(o) ,它相当于(Foo)o

通常,如果X是可再生类型Class clazz ,则clazz.cast(o)(X)o相同。

如果所有类型都是可恢复的,则方法Class.cast()因此是多余的且无用的。

不幸的是,由于当前版本的Java中的擦除,并非所有类型都可以恢复。 例如,类型变量不可恢复。

如果T是一个类型变量,则取消选中cast (T)o ,因为在运行时,JVM不知道T的确切类型,JVM无法测试o是否真的是T类型。 可能会错误地允许演员表,这可能会在以后引发问题。

这不是一个大问题; 通常当程序员做(T)o ,他已经推断出演员是安全的,并且在运行时不会引起任何问题。 应用程序逻辑检查强制转换。

假设在演员Class clazz有一个Class clazz ,那么我们就知道T在运行时是什么; 我们可以添加额外的运行时检查以确保o确实是T

 check clazz.isInstance(o); (T)o; 

这基本上是Class.cast()作用。

在任何情况下我们都不会期望演员表失败,因此在正确实现的应用程序中,检查clazz.isInstance(o)必须始终成功,因此clazz.cast(o)等同于(T)o – 再次,在假设代码是正确的。

如果可以certificate代码是正确的并且演员clazz.cast(o)是安全的,那么出于性能原因,人们可能更喜欢(T)oclazz.cast(o) 。 在另一个答案中提出的MutableClassToInstanceMap示例中,我们可以清楚地看到演员MutableClassToInstanceMap是安全的,因此简单(T)o就足够了。

class.cast专为generics类型而设计。

使用generics参数T构造类时,可以传入一个Class。 然后,您可以使用静态和动态检查进行转换,(T)不会给您。 它也不会产生未经检查的警告,因为它被检查(此时)。

对此的常见示例是从持久层检索使用类对象和某些条件引用的实体集合。 返回的集合可能包含未经检查的对象,因此如果您只是将其强制转换为指向G_H,则此时将抛出Cast Exception,而不是在访问值时抛出。

这方面的一个示例是当您从DAO检索一个返回未经检查的集合的集合时,并且在您的服务上迭代它,这种情况可能导致ClassCastException。

解决它的一种方法是,因为你有想要的类和未经检查的集合迭代它并将其转换到DAO中,将集合转换为已检查的集合,然后返回它。

因为你可能有这样的东西:

 Number fooMethod(Class clazz) { return clazz.cast(var); } 

Java中的“强制转换”,例如(Number)var ,其中括号内的东西是引用类型,实际上由两部分组成:

  • 编译时间:强制转换表达式的结果具有您投射到的类型
  • 运行时:它插入一个检查操作,基本上说,如果对象不是该类的实例,则抛出一个ClassCast Exception (如果你要转换的东西是一个类型变量,那么它检查的类将是类型变量的下限)

要使用语法,您需要在编写代码时知道类。 假设您在编译时不知道要转换为哪个类; 你只在运行时知道它。

现在你会问,那么铸造的重点是什么? 在编译时将表达式转换为所需类型不是转换点吗? 所以如果你在编译时不知道类型,那么在编译时没有任何好处,对吧? 没错,但这只是上面的第一项。 您忘记了演员表的运行时组件(上面的第二项):它会根据类检查对象。

因此,运行时Class.cast() (即Class.cast() )的目的是检查该对象是否为该类的实例,如果不是,则抛出exception。 它大致相当于此但更短:

 if (!clazz.isInstance(var)) throw new ClassCastException(); 

有些人提到Class.cast()也有一个很好的返回类型,它基于传入的类的类型参数,但这只是编译时Class.cast()提供的编译时特性。 因此,为此目的,使用Class.cast()是没有意义的。