为什么 NOT 可以将新的Object添加到List中,如果这个类型应该能够添加任何超类型的Apple?
import java.util.List;
import java.util.ArrayList;
class Apple{}
public class Macintosh extends Apple {
public static void main(String[] munch){
List<Apple> a = new ArrayList<Apple>();
basket(a);
}
static void basket(List<? super Apple> list){ list.add(new Object());}
}
如果我们将参数更改为列表列表,当然它可以工作:s
class Animal{}
class Dog extends Animal{}
class Cat extends Animal{}
public class Mixer<A extends Animal>{
public <C extends Cat> Mixer<? super Dog> useMe(A a, C c){
return new Mixer<Animal>();
}
}
为什么我们可以在返回时间使用Mixer如果之前的编译器不知道对象的Class,现在是因为是一个类?¿?
答案 0 :(得分:0)
您正在尝试向苹果列表添加不属于Apple的对象(对象不是Apple的一个子级)。因此,编译错误。
答案 1 :(得分:0)
您不能将除Apple及其子类型以外的任何内容添加到List<? super Apple>
,因为?意思是'某种类型'而不是'任何类型'。它是某种类型的实例列表,它是Apple或Apple的超类型,并且无法知道哪种类型的确切类型?装置
如果可以的话,我建议避免这些限制,他们经常没有帮助,很容易导致混淆。
答案 2 :(得分:0)
正如其他人所指出的,通配符类型是存在量化的类型,而不是普遍量化的。这意味着,当使用带有通配符的类型变量时,可以在写入时指定任何匹配类型,但在从变量读取时不能假设任何特定类型。在写作时,你可以控制选择,但在阅读时,其他人会为你选择它。
更多细节
您在写作时可以完全控制。方法的返回值将在return
语句中写入其正文内部。其参数将写入您调用方法的位置。您可以愉快地将特定类型分配给通配符return
语句,或将特定类型传递给通配符方法参数。
在阅读时强制选择。在调用方法的地方读取方法的返回值。其参数在其正文中读取,您可以在其中定义方法。当您尝试使用传递的basket()
时,您在list
内遇到了困难。
如果我们将参数更改为列表列表,当然它可以工作:s
这是一个完全不同的故事。 List
是原始类型。正如您自己发现的那样,如果您使用原始类型,则可以执行不安全的操作,例如向Orange
添加Object
或任何其他List<Apple>
。 Java支持原始类型主要是出于历史原因,如向后兼容性。他们的设计不健全。如果您以这种方式使用原始类型,则可能会在以后获得ClassCastException
:
List<Apple> a = new ArrayList<Apple>();
basket(a);
for (Apple apple : a) { // Is not assignable to Apple, throws ClassCastException
System.out.println(apple);
}