简体   繁体   English

Java泛型中的通配符

[英]Wildcards in java Generics

I know Generics are invariant: for any two distinct types Type1 and Type2, List< Type1> is neither a subtype nor a supertype of List< Type2> 我知道泛型是不变的:对于任何两个不同类型Type1和Type2,List <Type1>既不是List <Type2>的子类型也不是父类型

so 所以

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

but

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

let say if wildcard is Object so line 2 wil be 假设通配符是Object,那么第2行将

List<Object> sink = List<Number> nums 

It seems that the invariant rule not applied here 似乎不变规则在这里不适用

can anyone explain to me why line 2 is compiled without error ? 谁能向我解释为什么第二行编译时没有错误?

Thank so much 非常感谢

If I am not wrong, you wish to have an explanation on how is the below valid code: 如果我没看错,您希望对以下有效代码的解释:

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

Invariance is property of the class on how its type parameter affects its subtyping. 不变性是类的属性,它的类型参数如何影响子类型。

Generics are invariant, but wild cards exist to help us with with sub-typing. 泛型是不变的,但是存在通配符可以帮助我们进行子类型化。 They are not very useful as they dont representing anytype but represent a good hack. 它们不是非常有用,因为它们不代表任何类型,但是代表了不错的技巧。 Below is valid 以下有效

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

Better example: 更好的例子:

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

The above works, because d1 is of type List<? super Animal> 上面的作品,因为d1的类型为List<? super Animal> List<? super Animal> . List<? super Animal> You can imagine add function to behave like: 您可以想象add函数的行为如下:

boolean add(? super Animal e);

So to add method you can pass any variable that is subtype of ? super Animal 因此,要add方法,您可以传递子类型? super Animal任何变量? super Animal ? super Animal . ? super Animal And

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

So adding a Dog or Animal works. 因此,添加狗或动物的作品。 So d1 acts as a list that can take any parameter of type Animal or subtype if it. 因此, d1作为一个列表,可以接受任何类型为Animal或subtype(如果有)的参数。

Similarly, you can also have below. 同样,您也可以在下面。 But technically you cant add anything to this list. 但是从技术上讲,您不能在此列表中添加任何内容。 If there existed sometype in java that is subtype of every type, then you could properly add element of that type to it. 如果java中存在某个类型,它是每种类型的子类型,则可以向该类型中适当添加该类型的元素。 Nothing Else. 没有其他的。

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

Look at this answer for more info . 查看此答案以获取更多信息

The invariant rule does indeed apply. 不变规则确实适用。 The statement: 该声明:

List<? super Number> sink = nums; 

just doesn't work they way you are thinking. 只是按照他们的想法行不通。

I expect that you think that you can assign an object of type ArrayList to a variable of type List<? super Number> 我希望您认为可以将ArrayList类型的对象分配给List<? super Number>类型的变量List<? super Number> List<? super Number> because the former is a subclass of the latter. List<? super Number>因为前者是后者的子类。 This would break the invariant rule, but this is not what is happening. 这将打破不变的规则,但是事实并非如此。

The List<? super Number> List<? super Number> List<? super Number> variable represents the set of all possible List where someClass is Number or is an ancestor of Number. List<? super Number>变量表示所有可能的List的集合,其中someClass是Number或Number的祖先。

let say if wildcard is Object so line 2 wil be 假设通配符是Object,那么第2行将

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

In this context the ? 在这种情况下? doesn't get set arbitrarily, so this doesn't happen. 不会被任意设置,因此不会发生。

Lets have: 让我们:

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

That is why you cannot make such assignment. 这就是为什么您无法进行此类分配。 I think compiler doesn't treat direct assignment of new ArrayList<Integer>() other then existing variable li . 我认为编译器除了现有变量li ,不处理对new ArrayList<Integer>()直接分配。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM