我对下面的代码有以下疑问:
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;
会给你一个未经检查的赋值警告,因为 obj
是 String
的 GenericBridgeMethods
无法在运行时检查。但是,如果您这样做,则会出现相同的警告:
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
,即使您知道它会在运行时失败。原因是因为编译器只知道 obj
是 List
的一种。由于 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
不起作用,因为 Number
和 ArrayList
都是类,而不是接口(interface)。因为 Java 不允许从多个类 继承,对于一个对象同时是Number
和ArrayList
的实例,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/