java泛型中的通配符

时间:2015-02-15 20:15:59

标签: java generics

我知道泛型是不变的:对于任何两种不同的类型Type1和Type2,  列表与LT;类型1>既不是List的子类型也不是超类型< 类型2>

所以

List<someObject> nums = new ArrayList<someObject>(); // this is correct
List<Object> nums = new ArrayList<subObject>(); // this is  not correct

但是

List<Number> nums = new ArrayList<Number>();
List<? super Number> sink = nums;   ????(line 2)

如果通配符是Object,那么第2行将是

List<Object> sink = List<Number> nums 

似乎这里没有应用不变规则

有人可以向我解释为什么第2行编译没有错误吗?

非常感谢

3 个答案:

答案 0 :(得分:2)

如果我没错,您希望对以下有效代码的解释如下:

List<Number> nums = new ArrayList<Number>();
List<? super Number> sink = nums;

Invariance是类的属性,它的类型参数如何影响其子类型。

泛型是不变的,但存在通配符以帮助我们进行子类型输入。它们不是很有用,因为它们不代表任何类型但代表一个好的黑客。以下是有效的

List<Animal>  <: List<?>
List<?>       <: List

更好的例子:

List<? super Animal> d1= new ArrayList<Animal>();
d1.add(new Animal());
d1.add(new Dog());

上述方法有效,因为d1的类型为List<? super Animal>。你可以想象add函数的行为如下:

boolean add(? super Animal e);

因此,对于add方法,您可以传递? super Animal子类型的任何变量。和

Animal <: ? super Animal
Dog    <: ? super Animal

所以添加狗或动物作品。因此d1充当一个列表,可以接受Animal类型的任何参数或子类型。

同样,你也可以在下面。但从技术上讲,你无法在此列表中添加任何内容。如果java中存在某种类型,即每种类型的子类型,那么您可以正确地向其添加该类型的元素。没什么。

ArrayList<? extends Animal> d1  = new ArrayList<Animal>();

请查看此答案,了解更多info

答案 1 :(得分:1)

不变规则确实适用。声明:

List<? super Number> sink = nums; 

只是按照你的想法行事。

我希望您认为可以将ArrayList类型的对象分配给类型为List<? super Number>的变量,因为前者是后者的子类。这会破坏不变规则,但这不是正在发生的事情。

List<? super Number>变量表示所有可能的List的集合,其中someClass是Number或者是Number的祖先。

  

如果通配符是Object,那么第2行将是

     `List<Object> sink = List<Number> nums `

在这种背景下?没有任意设置,所以这不会发生。

答案 2 :(得分:-1)

让我们:

List<Integer> li = new ArrayList<>();
List<Object> lo = new ArrayList<>();
l = lo;//not allowed
lo.add("string");
Integer i = li.get(0);//that is string there

这就是为什么你不能做这样的任务。我认为编译器不会直接分配new ArrayList<Integer>()以外的现有变量li