为什么下面的泛型代码在运行时不引发异常?
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);
}
}
答案 0 :(得分:4)
除非您实际编写方法,否则不会创建桥(合成方法),就像在后续测试中所做的那样,您在代码中将public boolean add(String o){return super.add(o);}
放入了代码。
当您对类型为.get(someInt)
的表达式调用StringList
时,编译器可以看到您的StringList
类型,即使它是ArrayList<String>
的子类型,也不会没有任何带有签名String get(int)
的方法。因此,它将在字节码中生成对Object get()
方法的调用,并(如果需要)强制转换,并且在Java方面,它的作用就像StringList
上的get方法返回一样串。即使在字节码级别也没有。
如果您随后使String get(int)
方法出现(例如,通过子类化StringList
或通过编辑源代码并仅重新编译该文件),则仅会生成bridge方法。因为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);
}
}