java通用和通配符

java generic and wild card

在Java泛型中,我理解了什么是MealCad、Supe和Exchange,但没有得到为什么不允许我添加任何东西,为什么允许我在层次结构中添加一些类型,而不在层次结构中添加呢?

1
2
class Animal {}
class Cat extends Animal{}

以下方法可以获取动物列表或动物子列表,即猫,但没有其他任何方法我不允许添加任何东西,如果试图添加,编译器会阻止我为什么?

1
2
3
4
void addAminal(List<? extends Aminal> aList){
       aList.add(new Cat()); // compiler error
       aList.add(new Animal()); // compiler error
}

现在,下面的方法可以获取任何动物列表或任何超级动物类型,但没有动物的子类型,我可以添加对象到动物或更低层次,所以当我尝试添加对象时,编译器会抱怨为什么?

1
2
3
4
5
void addAnimal(List<? super Animal> aList){
     aList.add(new Animal()); // no error
     aList.add(new Cat());     // no error
     aList.add(new Object()); // compiler error why ?
}

谢谢艾莉亚


假设您定义了一个新类:

1
class Tabby extends Cat {}

然后你做了以下的事情:

1
2
List<Tabby> aList = new ArrayList<Tabby>();
addAnimal(aList);

毫不奇怪,这个列表不应该有一个动物,甚至一只猫,不是一个选项卡,但如果编译器没有标记错误,这是你会有的。

原因是侯先生已经指定addAnimal列出了一些可以扩展动物的东西,但是有些东西可能是非常严格的。然而,这将编译:

1
2
3
4
void addAnimal(List<Animal> aList){
    aList.add(new Cat()); // OK
    aList.add(new Animal()); // OK
}

使用super也会起作用,因为CatAnimal的实例是Animal的任何超类的实例。


List是指List,其中XAnimal的未知亚型。

因此它有方法

1
2
void add(X item);
X get(int i);

你不能称之为添加(cat),因为我们不知道cat是否是x的子类型。由于X未知,我们知道的唯一值是X的子类型是null,所以你可以使用add(null)但没有其他值。

我们可以执行Animal a = list.get(i),因为方法返回XXAnimal的一个子类型。所以我们可以称之为get(i),把回报值当作动物来对待。

相反,List表示List,其中Y是未知的Animal的超类型。现在我们可以称为add(cat),因为猫是动物的一个亚型,动物是Y的一个亚型,所以猫是Y的一个亚型,add(Y)接受猫。另一方面,由于动物不是返回型Y的超型,所以Animal a = list.get(0)现在不起作用;唯一已知的Y的超型是宾语,所以我们只能做Object o = list.get(0)


好吧,当你说ArrayList<?扩展动物>您指定此列表将包含任何特定类型(如?指一种特定的/确定的类型),属于动物或从动物继承而来的任何事物,但不属于确定的事物。因此,最终,由于泛型是用橡皮擦概念实现的(该概念将程序中的每个泛型类型替换为非泛型上界),所以这个列表应该包含一个特定的类型,但由于(<?扩展动物>)您不知道这是哪种特定类型。因此,即使类型是从动物继承的,也不允许添加。

但当你说ArrayList<?超级动物>,表示arraylist包含从动物派生的特定类型,也就是说,其基础或超级类型是动物的对象。因此,将动物或从动物身上获得的任何东西放入此列表是安全的。这个列表就是这样处理的,并且可以像前面提到的那样添加对象。因此它起作用了。

希望有帮助!


泛型只允许添加给定类型参数的类型(或子类型)的对象。如果你把放进去,这意味着这个列表有一些类型,它是动物的一个子类。由于您试图添加一只猫,因此必须确保它确实是猫的列表,而不是狗的列表。
基本上,当您使用通配符时,您将无法将新项目添加到这样的列表中(注意:我没有完全的知识,这可能不完全正确,但看起来是这样的。如果我错了请原谅我)

如果你想在列表中添加任何动物,只需使用List