Java 泛型 : Casting a raw type to any reifiable type doesn't generate unchecked cast warning

标签 java generics

我对下面的代码有以下疑问:

public class GenericBridgeMethods <T> {

    public static void main(String[] args) {
        List obj = new ArrayList<Integer>();
        List <?> l1 = (List<?>) obj; // clause 1
        GenericBridgeMethods <?> g1 = (GenericBridgeMethods<?>) obj; // clause 2
   }

}

一个。第 1 条当然不会给出 unchecked cast warning
b.第2条也没有给出unchecked cast warning

我注意到从原始类型 (obj) 到任何可具体化类型(如 GenericBridgeMethods 或 GenericBridgeMethods )的转换不会给出未经检查的转换警告。如果运行此代码,将在第 2 条出现运行时错误。

编译器是否应该在第 2 条给出警告

编辑 1:

    ArrayList a1 = new ArrayList<Integer>(); // clause 3
    Number n1 = (Number)a1; // clause 4 ERROR
    Comparable c1 = (Comparable)a1; // clause 5

    List l1 = new ArrayList<Integer>(); // clause 6
    Number n2 = (Number)l1; // clause 7
    Comparable c2 = (Comparable)l1; // clause 8

谁能解释一下为什么只有第4条有错误?

最佳答案

好吧,首先在 GenericBridgeMethods 中定义了它,T 不是可具体化的类型。 Reifiable 意味着该类型将被编码到类中并在运行时可用。 T 不是这样。

第 2 条不会给出运行时警告,因为它已被检查:将进行运行时检查以确保 obj 类型可分配给 GenericBridgeMethods类型。由于您已选择通配符作为类型参数,因此无需检查有关 T 的任何内容。

如果另一方面你做了这样的事情:

GenericBridgeMethods<String> g1 = (GenericBridgeMethods<String>) obj;

给你一个未经检查的赋值警告,因为 objStringGenericBridgeMethods无法在运行时检查。但是,如果您这样做,则会出现相同的警告:

List<String l1 = (List<String>) obj;

编辑

如果您对为什么编译器允许您尝试将 List 转换为 GenericBridgeMethods 感到困惑,答案是因为编译器无法知道GenericBridgeMethods 及其子类的整个层次结构。可能有一个 GenericBridgeMethods 的子类实现了 List,在这种情况下,转换可能是合法的。

但是,如果您将 GenericBridgeMethods 设为最终类(并因此阻止它拥有子类),您得到一个编译错误。在这种情况下,您将收到不可转换的类型错误。

只是为了向您展示您的问题与可具体化的类型和泛型无关,请看一下:

public static void main(String[] args) {
   List obj = new ArrayList<Integer>();

   //this is allowed (no warning), even though it will fail at runtime
   CharSequence sequence = (CharSequence) obj; 
}

您可以显式地将 obj 转换为 CharSequence,即使知道它会在运行时失败。原因是因为编译器只知道 objList 的一种。由于 List 是一个接口(interface),因此 CharSequence 的实现可能也是一个 List,因此必须允许转换。

每个 显式转换都有一定程度的在运行时失败的可能性。否则,这将是一个冗余转换,编译器应该允许您省略显式转换。

编辑 - 关于您的“编辑 #1”

ArrayList a1 = new ArrayList<Integer>(); // clause 3
Number n1 = (Number)a1; // clause 4 ERROR
Comparable c1 = (Comparable)a1; // clause 5

List l1 = new ArrayList<Integer>(); // clause 6
Number n2 = (Number)l1; // clause 7
Comparable c2 = (Comparable)l1; // clause 8

您想知道为什么只有“第 4 条”不能编译。我想我已经在上面和评论中对此进行了解释,但我将逐步为您完成这个具体示例。

ArrayList a1 = new ArrayList<Integer>(); // clause 3
Number n1 = (Number)a1; // clause 4 ERROR

a1 转换为 Number 不起作用,因为 NumberArrayList 都是类,而不是接口(interface)。因为 Java 不允许从多个 继承,对于一个对象同时是NumberArrayList 的实例,Number 必须是 ArrayList 的子类,反之亦然。这在编译时是不正确的。

ArrayList a1 = new ArrayList<Integer>(); // clause 3
Comparable c1 = (Comparable)a1; // clause 5

由于 Comparable 是一个接口(interface),ArrayList 的子类可能是一个 Comparable

List l1 = new ArrayList<Integer>(); // clause 6
Number n2 = (Number)l1; // clause 7

由于 List 是一个接口(interface),Number 的子类可以实现 List。编译器在检查 l1 包含 ArrayList 的转换时并不知道。

关于Java 泛型 : Casting a raw type to any reifiable type doesn't generate unchecked cast warning,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7676981/

相关文章:

java - 退出时如何保存 Activity 的状态?安卓

java - Jackson 和泛型类型引用

generics - 当其中一个是本地引用时,如何在类型约束中编写引用的生存期?

.net - 定义具有相同名称和不同数量类型参数的泛型类 (C++/CLI)

java - 在 Spring 4 中干燥一个通用的 RedisTemplate

vb.net - 通用列表复制引用而不是创建复制列表

用于检查邮箱中电子邮件的Java示例代码?

java - 什么是非法反射访问?

Java2d : Translate the axes

java - 为什么我使用 java post-request 来响应状态代码 500 的内部服务器错误?