我有以下课程
public class Animal
public class Dog extends Animal
public class Cat extends Animal
对于测试我有一个驱动程序类。
public class Driver {
public static void main(String[] args){
List<? extends Animal> animalList = Arrays.<Dog>asList(new Dog(), new Dog(), new Dog());
animalList.add(new Dog()) // Compilation error
}
}
默认情况下,list是不变类型的容器。例如,我们有List<Object> objectList
,ArrayList<String> stringList
我们无法将stringList替换为objList。这将导致编译错误
我的尝试是在Driver类中创建list co-variant。
根据<? extends Animal>
,我们可以应用任何动物类型的对象,包括动物类型。
但是我在指定的行中遇到了编译问题。有人可以从理论上解释我哪里出错了。
答案 0 :(得分:4)
我认为你误解了通用通配符(?
)。来自Java tutorial on the subject:
与往常一样,使用灵活性需要付出代价 通配符。这个价格是写入形状现在是非法的 在方法体内。例如,这是不允许的:
public void addRectangle(List<? extends Shape> shapes) { // Compile-time error! shapes.add(0, new Rectangle()); }
您应该能够弄清楚为什么不允许上面的代码。该
shapes.add()
的第二个参数的类型是? extends Shape
- an 未知的Shape
子类型。由于我们不知道它是什么类型,我们 不知道它是否是Rectangle
的超类型;它可能会也可能不会 这样的超类型,因此传递Rectangle
是不安全的。
Java泛型集合不是协变的;见例如Java theory and practice: Generics gotchas获得解释。
答案 1 :(得分:1)
java没有一个非常强大的类型系统,这意味着:你不能这样做。
悲伤的回答,但是确实如此。来自维基百科:与数组不同,泛型类既不是协变也不是 逆变。例如,
的子类型List<String>
和List<Object>
都不是 另一个
http://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)#Java
答案 2 :(得分:0)
更改您的代码:
public class Driver {
public static void main(String[] args){
List<? extends Animal> animalList = Arrays.<Cat>asList(new Cat(), new Cat(), new Cat());
animalList.add(new Dog()) // Compilation error
}
}
并且编译错误更有意义吗?所有Java都必须脱离你为animalList
提供的类型。 Java知道右侧的东西可能是Cat
个对象的列表,所以它不会让你放入Dog
。将您的代码更改为
List<Animal> animalList = Arrays.<Animal>asList(new Dog(), new Dog(), new Dog());
这样就可以了。