考虑:
public class Parent {
}
public class Child extends Parent {
}
ArrayList<Parent> ps= new ArrayList<Child>(); \\wont compile
ArrayList<? extends Parent> ps2= new ArrayList<Child>(); \\works
为什么在使用<? extends Parent>
时默认不假设<Parent>
?我的意思是我无法想到一个用例,假设每个子项都是父项,您会想到任何意外行为吗?
编辑:
一个更有用的示例:
public static final void main(String[] args) {
ArrayList<Child> children=new ArrayList<Child>();
children.add(new Child());
children.add(new Child());
computeSomething1(children); \\doesnt compile
computeSomething2(children); \\compiles
}
public static int computeSomething1(ArrayList<Parent> ps) {
return 1;
}
public static int computeSomething2(ArrayList<? extends Parent> ps) {
return 1;
}
答案 0 :(得分:2)
如果java这样做了,您很容易得到污染列表。假设Java遵循您的建议,并允许您将List<Child>
分配给类型List<Parent>
的变量。然后,这将是可能的:
static class Parent {}
static class Child extends Parent {}
static class IllegitimateChild extend Parent {}
public static void main(String args[]) {
List<Child> children = new ArrayList<>();
computeSomething(children);
Child c = children.get(0); //WTF - ClassCastException?? IllegitimateChild is not a Child
}
public static void computeSomething(List<Parent> items) {
parents.add(new IllegitimateChild());
}
要解决这个问题,如果需要的话,java使您显式声明一个有界通配符。这样就可以在编译时捕获此类错误。
public static void main(String[] args) {
List<? extends Parent> items = new ArrayList<Child>();
items.add(new IllegitimateChild()); // Compiler error
items.add(new Child()); // Compiler error
}
以上两种编译器错误都是Java所说的:“此列表中的元素类型对我来说是未知的(?
),因此我不允许您将其放在此处,因为它可能违反了知道此类型的其他引用此列表的合同。” ? extends Parent
而不只是?
的事实实际上确实有助于编译器推断有关方法的 return type 的信息(例如,它知道它可以分配调用{{ 1}}转换为items.get(0)
变量,即使它不知道具体类型也是如此。