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

时间:2011-10-26 08:38:20

标签: java generics language-construct

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

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

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

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

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

8 个答案:

答案 0 :(得分:7)

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

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

编辑:使用google guava的几个例子:

答案 1 :(得分:4)

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

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

一般情况下,使用更简单的铸造,除非它不够。

答案 2 :(得分:2)

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

答案 3 :(得分:2)

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

一般情况下,如果X可再生类型Class<X> clazz,则clazz.cast(o)(X)o相同。

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

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

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

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

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

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

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

我们永远不会指望演员阵容在任何情况下失败,因此在正确实施的应用中,支票clazz.isInstance(o)必须始终成功,因此clazz.cast(o)相当于(T)o - 再次,假设代码是正确的。

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

答案 4 :(得分:1)

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

使用泛型参数T构造类时,可以传入一个 类。然后,您可以使用静态和动态进行演员 检查,哪(T)不给你。它也不会产生未检查 警告,因为它被检查(在那一点)。

答案 5 :(得分:1)

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

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

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

答案 6 :(得分:0)

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

Number fooMethod(Class<? extends Number> clazz) {
    return clazz.cast(var);
}

答案 7 :(得分:0)

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

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

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

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

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

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

有些人提到Class.cast()也有一个很好的返回类型,它基于传入的类的类型参数,但这只是一个由编译时强制转换提供的编译时功能无论如何。因此,为此目的,使用Class.cast()

是没有意义的