20

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

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

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

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

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

4

8 回答 8

8

我认为它并不像您所展示的那样经常使用。我见过的最常见的用途是使用泛型的人试图做与此等效的事情:

public static <T extends Number> T castToNumber(Object o) {
    return (T)o;
}

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

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

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

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

于 2011-10-26T08:47:45.930 回答
4

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

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

一般来说,使用更简单的转换,除非它还不够。

于 2011-10-26T08:44:42.867 回答
2

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

于 2011-10-26T08:45:43.580 回答
2

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

一般来说, ifX是可具体化的类型,并且Class<X> clazz, thenclazz.cast(o)与 相同(X)o

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

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

ifT是一个类型变量, cast(T)o是未检查的,因为在运行时,JVM 不知道 的确切类型T,JVM 无法测试 ifo是否真的是 type T。演员可能被错误地允许,这可能会在以后引发问题。

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

假设 aClass<T> clazz在强制转换时可用,那么我们确实知道T运行时是什么;我们可以添加额外的运行时检查以确保o确实是T.

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

这基本上就是Class.cast()这样做的。

我们永远不会期望强制转换在任何情况下都会失败,因此在正确实现的应用程序中,检查clazz.isInstance(o)必须始终成功,因此clazz.cast(o)相当于(T)o- 再次假设代码是正确的。

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

于 2011-10-26T11:36:57.503 回答
1

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

一个示例是,当您从返回未经检查的集合的 DAO 中检索集合并在您的服务上对其进行迭代时,这种情况可能会导致 ClassCastException。

解决它的一种方法,因为您有想要的类并且未检查的集合对其进行迭代并将其强制转换到 DAO 中,从而将集合转换为已检查的集合,然后将其返回。

于 2011-10-26T09:04:53.843 回答
1

class.cast 是为泛型类型设计的。

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

于 2011-10-26T08:45:36.887 回答
0

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

Number fooMethod(Class<? extends Number> clazz) {
    return clazz.cast(var);
}
于 2011-10-26T08:44:51.627 回答
0

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

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

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

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

因此,运行时强制转换(即Class.cast())的目的是检查对象是否是类的实例,如果不是,则抛出异常。它大致相当于这个但更短:

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

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

于 2011-10-26T20:32:00.367 回答