关于以下代码,我有以下问题:
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条当然不会给出未经检查的投射警告 湾第2条也没有给出未经检查的投射警告
我注意到从原始类型(obj)到ANY可再现类型(如GenericBridgeMethods或GenericBridgeMethods&lt;?&gt;)的强制转换不会给出未经检查的强制转换警告。如果运行此代码,则第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条有错误吗?
答案 0 :(得分:11)
好吧,首先在GenericBridgeMethods
中定义它,T
不是可再生类型。可恢复意味着类型将被编码到类中并且将在运行时可用。 T
的情况并非如此。
第2条没有给出运行时警告,因为它被检查:将有obj
类型可分配给GenericBridgeMethods
类型的运行时检查。由于您选择了通配符作为类型参数,因此不需要检查T
。
如果另一方面你做了这样的事情:
GenericBridgeMethods<String> g1 = (GenericBridgeMethods<String>) obj;
将为您提供未经检查的分配警告,因为obj
是GenericBridgeMethods
String
的事实无法在运行时检查。但是,如果您这样做,则会出现相同的警告:
List<String l1 = (List<String>) obj;
如果您对编译器允许您尝试将List
强制转换为GenericBridgeMethods
的原因感到困惑,那么答案是因为编译器无法知道{{1}的整个层次结构和它的子类。可能有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
的实现可能也是CharSequence
,因此必须允许强制转换。
每个显式转换都有一定程度的可能性,它可能在运行时失败。否则,它将是一个冗余的强制转换,编译器应该允许你省略显式强制转换。
List
您想知道为什么只有“第4条”无法编译。我想我已经在上面和评论中对此进行了解释,但我将逐步为您提供这个具体示例。
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
将ArrayList a1 = new ArrayList<Integer>(); // clause 3
Number n1 = (Number)a1; // clause 4 ERROR
投射到a1
不起作用,因为Number
和Number
都是类,而不是接口。因为Java不允许从多个类继承,所以对象必须是ArrayList
和Number
的实例,ArrayList
必须是Number
,反之亦然。众所周知,这在编译时是不正确的。
ArrayList
由于ArrayList a1 = new ArrayList<Integer>(); // clause 3
Comparable c1 = (Comparable)a1; // clause 5
是一个接口,Comparable
的子类可能是ArrayList
。
Comparable
由于List l1 = new ArrayList<Integer>(); // clause 6
Number n2 = (Number)l1; // clause 7
是一个接口,List
的子类可以实现Number
。编译器不知道何时检查List
持有l1
的演员表。