Java - 泛型 - Class&#34; Class <! - ? - >&#34;的显式强制转换和强制转换方法

时间:2014-05-26 04:37:47

标签: java generics casting effective-java

为什么在cast类上使用Class<?>方法会在编译时产生未经检查的警告?

如果您在cast方法中查看,则会找到以下代码:

public T cast(Object obj) 
{
    if (obj != null && !isInstance(obj))
        throw new ClassCastException(cannotCastMsg(obj));
    return (T) obj; // you can see there is a generic cast performed here
}

如果我进行通用演员表,编译器会抱怨说有unchecked warning


其他背景资料

您可以在Book Effective Java 2版本(第166页)(pdf)中找到我如何得出这个问题的示例。

作者写了这段代码

public <T> T getFavorite(Class<T> type) 
{
    return type.cast(favorites.get(type));
}

VS

public <T> T getFavorite(Class<T> type) 
{
    return (T) (favorites.get(type));
}

我只是没有区别,为什么编译器抱怨未经检查的警告。最后,两段代码都进行了显式转换(T) object,不是吗?

2 个答案:

答案 0 :(得分:7)

如果没有@SuppressWarnings("unchecked")注释,java.lang.Class的源代码会在编译期间产生警告 。不会生成警告,因为JDK类位于已编译的库中。我确信自己编译JDK会产生一些警告。

@Bohemian评论说这是一个“官方kludge”本质上是正确的,并且有许多这样的代码示例。 (另一个例子是java.lang.Enum#getDeclaringClass。)使用是安全的,因为编写的逻辑是正确的,它存在,所以你不必自己编写这种丑陋的东西。

我的建议是不要过多考虑这个实现:重要的是java.lang.Class#cast符合已检查强制转换的语义。

答案 1 :(得分:1)

为了强制执行内存安全,Java确保引用类型的变量实际上包含对该类型对象(或其子类型)的引用。演员指令可能会违反此不变量,即我们可以写:

Object o = new Integer(42);
String s = (String) o;  // compiles, but throws ClassCastException at runtime

为了防止这种情况,强制转换指令将检查引用的对象的类型,如果不是则抛出ClassCastException。

在将泛型引入Java语言之前,上述内容适用于所有演员。但是,通过类型擦除实现泛型,运行时不知道类型参数代表哪个类,因此如果涉及类型参数则不能执行此检查。

这就是为什么规范区分已检查的强制转换(只有在类型正确时才能在运行时成功)和未经检查的强制转换(即使不是类型正确也可能成功,导致堆污染,并且可能在以后出现类型错误)。例如:

class C<T> {
    final T field;

    C(Object o) {
        this.field = (T) o; // unchecked. Will never throw a ClassCastException.
    }
}

boolean test() {
    C<String> c = new C<String>(42);
    return c.field.startsWith("hello"); // throws ClassCastException, even though there is no cast in the source code at this line!
}

也就是说,未经检查的强制转换可能不安全,应该避免使用。

在这种背景下,很容易看到反射强化转换(Class.cast()方法)被检查,因为它们实际上是在方法本身中实现检查:

public T cast(Object obj) 
{
    if (obj != null && !isInstance(obj))
        throw new ClassCastException(cannotCastMsg(obj));
    return (T) obj;
}

这个安全网就是为什么当演员阵容涉及类型参数时,反射演员比普通演员更受欢迎。