为什么下面的泛型代码不会在运行时抛出异常?
public static void main(String[] args) {
((List)new ListString()).add(3);
}
static class ListString extends ArrayList<String>{
}
我知道这不是应该如何使用泛型但我认为the bridge methods会通过添加以下方法来解决这个问题,这将抛出一个ClassCastException.
public boolean add(Object o){
return add((E)o);
}
注意:如果按照以下方法修改ListString类,这确实会引发ClassCastException:
static class ListString extends ArrayList<String>{
@Override
public boolean add(String o){
return super.add(o);
}
}
除非您实际编写方法,否则不会创建桥(合成方法),就像您在后续测试中所做的那样,您在代码中放置了public boolean add(String o){return super.add(o);}
。
当你在.get(someInt)
类型的表达式上调用StringList
时,编译器可以看到你的StringList
类型,即使它是ArrayList<String>
的子类型,也没有任何带有签名String get(int)
的方法。因此,它在字节码中生成对Object get()
方法的调用,此外(如果需要)生成一个强制类型,并且在java方面,它就像在StringList
上的get方法返回String一样。即使在字节码级别它也没有。
如果然后出现一个String get(int)
方法,例如通过继承StringList
,或者通过编辑源并重新编译该文件,那么只有这样才能生成桥接方法。因为java是动态调度,所以总是使用该桥。桥梁施放和调用(或调用和施放,取决于桥梁是否覆盖返回类型的恶作剧或参数恶作剧)。
你可以使用javap -v
来验证所有这些:我强烈推荐所有发现这个有趣的人,并且想要确切地知道这是如何有效地探索这个之间的输出差异:
import java.util.*;
public class Test extends ArrayList<String> {
public static void main(String[] args) {
List raw = new Test();
raw.add(3);
}
}
还有这个:
import java.util.*;
public class Test extends ArrayList<String> {
public static void main(String[] args) {
List raw = new Test();
raw.add(3);
}
public boolean add(String o) {
return super.add(o);
}
}