5

假设有以下代码:

@SuppressWarnings("unchecked")
public static  <T> T implicitCaster(Class<T> cls, Object o) {
    return (T) o;
}

public static <T> T reflectionCaster(Class<T> cls, Object o) {
    return cls.cast(o);
}

代码在这两种情况下都按预期工作,但在原语中发现了以下异常:

public static void main(String[] args) {
    System.out.println(implicitCaster(int.class, 42));
    System.out.println(reflectionCaster(int.class, 42));
}

第一个调用按预期工作,但第二个调用 throws java.lang.ClassCastException

这是忽略自动装箱的极端情况吗?或者在这种情况下,反射投射是否不可能提供自动装箱?还是有其他原因导致这种不一致?

编辑:调用此代码按预期工作:

public static void main(String[] args) {
    System.out.println(implicitCaster(Integer.class, 42));
    System.out.println(reflectionCaster(Integer.class, 42));
}
4

1 回答 1

3

这是由于类型擦除而发生的。

在运行时,泛型类型参数不存在。
将对象强制转换为泛型类型参数无效。(这就是为什么你得到未经检查的演员警告)

因此,您的第一行自动装箱42Object传递给该方法。
然后该函数返回那个Object,它被传递给System.out.println.


您的第二次调用调用原始类型的cast方法。 这会引发异常,因为无法将对象转换为原始类型。(自动装箱是一个纯粹的编译时特性,所以它没有帮助)int

cast() 检查isInstance()以验证强制转换是否有效时会发生错误。

文档isInstance()

具体来说,如果此 Class 对象表示已声明的类,则如果指定的 Object 参数是表示的类(或其任何子类)的实例,则此方法返回 true;否则返回 false。如果此 Class 对象表示一个数组类,如果指定的 Object 参数可以通过恒等转换或扩展引用转换转换为数组类的对象,则此方法返回 true;否则返回 false。如果此 Class 对象表示一个接口,则如果指定 Object 参数的类或任何超类实现此接口,则此方法返回 true;否则返回 false。如果此 Class 对象表示原始类型,则此方法返回 false。

(重点补充)


您的编辑有效,因为您不再使用原始类型。
在这两种情况下,编译器都会自动装箱42,以便可以将其作为对象传递。

和以前一样,第一次调用没有效果。
第二个调用验证装箱的整数实际上是Integer类的一个实例,然后返回它。

于 2013-07-11T15:02:15.073 回答