简体   繁体   English

Java泛型之间的通配符列表和通配符框列表之间的区别?

[英]Java Generics Difference between List of Wildcard and List of Box of Wildcard?

Why is 为什么是

List<?> list = new ArrayList<Object>();

while at the same time 同时

List<Box<?>> boxList = new ArrayList<Box<Object>>();

is not allowed 不被允许

Also what does List<? extends Box<?>> 还有List<? extends Box<?>> List<? extends Box<?>> mean. List<? extends Box<?>>意思。

Because a List<Box<?>> accepts boxes containing anything. 因为List<Box<?>>接受包含任何内容的框。 The following is thus valid: 因此,以下内容有效:

List<Box<?>> boxes = new ArrayList<>();
boxes.add(new Box<Integer>());
boxes.add(new Box<String>());

Whereas a List<Box<Object>> only accepts instances of Box<Object> . List<Box<Object>>仅接受Box<Object>实例。 The following is thus invalid, since a Box<Integer> and a Box<String> are not Box<Object> . 由于Box<Integer>Box<String>不是Box<Object> ,因此以下内容无效。

List<Box<Object>> boxes = new ArrayList<>();
boxes.add(new Box<Integer>());
boxes.add(new Box<String>());

Now if your question is "why is Box<String> not a Box<Object> " the answer is that if it were, you could do the following, which would ruin the type-safety of generic types: 现在,如果您的问题是“为什么Box<String>不是Box<Object> ”,那么答案是,如果是,则可以执行以下操作,这将破坏泛型类型的类型安全性:

Box<Integer> boxOfIntegers = new Box<>();
Box<Object> box = boxOfIntegers; // this is actually invalid
box.add("I'm a string in a box of integers. Ouch!");

Your question is a classic generic puzzle. 您的问题是一个经典的通用难题。 Often our brain is smart enough to infer new rules from known ones, but that's not the case with generics. 通常,我们的大脑足够聪明,可以从已知规则中推断出新规则,但对于泛型而言并非如此。 Your question illustrates two common problems with wildcards: 您的问题说明了通配符的两个常见问题:

  • You cannot assign a List<Box<Object>> to a List<Box<?>> 您不能将List<Box<Object>>分配给List<Box<?>>
  • You can actually call add() on a List<Box<?>> while you can't on a List<?> 实际上,您可以在List<Box<?>>上调用add() ,而不能在List<?>上调用

The solution to the first problem is that generics are invariant: there's no subtype relation, no matter what types are given to the type variables, unless there are wildcards involved. 第一个问题的解决方案是泛型是不变的:无论将什么类型赋予类型变量,都没有子类型关系,除非涉及通配符。 Even if Box<Object> is a subtype of Box<?> the subtype relation does not hold for the enclosing lists. 即使Box<Object>Box<?>的子类型,该子类型关系也不适用于封闭列表。

The rule for problem #2 is that wildcard are not captured recursively. 问题2的规则是不递归捕获通配符。 In fact new ArrayList<Box<?>>() is a valid expression, while new ArrayList<?>() is not. 实际上, new ArrayList<Box<?>>()是有效的表达式,而new ArrayList<?>()不是。 Also, as I said previously, you can add elements to a List<Box<?>> because the instatiation of the generic type List<E> yields: 另外,正如我之前所说,您可以将元素添加到List<Box<?>>因为通用类型List<E>的实例化会产生:

// This actually doesn't compile, it's just an explanation of the
// instantiation process
public interface List<Box<?>> {
  void add(Box<?> box);
}

List<A> is a subtype of List<?> , where A is a type (that satisfies the bounds of the wildcard, if any). List<A>List<?>的子类型,其中A是一种类型(满足通配符的范围,如果有的话)。

However, List<A> is not a subtype of List<B> , if A and B are types that are different (regardless of any sub typing relationship between A and B ). 但是,如果AB是不同的类型(不管AB之间A任何子类型关系),则List<A>不是List<B>子类型。

You have probably seen the case where List<String> is not a subtype of List<Object> , even though String is a subtype of Object . 您可能已经看到List<String>不是List<Object>的子类型的情况,即使StringObject的子类型。 (I will not go into the reasons here.) (我不会在这里讨论原因。)

The same thing is happening where List<Box<String>> is not a subtype of List<Box<?>> , even though Box<String> is a subtype of Box<?> . 即使Box<String>Box<?>的子类型,如果List<Box<String>>不是List<Box<?>>的子类型,也会发生同样的事情。 Note that even though there is a ? 请注意,即使有一个? in there somewhere, it is deep inside as part of the type Box<?> . 在某处,它是Box<?>类型的一部分在内部深处。 The ? ? does not act at the level of the parameter of List , so it does not allow you to take different types of lists. 不会在List的参数级别上起作用,因此不允许您采用其他类型的列表。

If you want a type that can accept List<Box<String>> and List<Box<Integer>> , etc., you may want to use List<? extends Box<?>> 如果要使用可以接受List<Box<String>>List<Box<Integer>>等的类型,则可能要使用List<? extends Box<?>> List<? extends Box<?>> . List<? extends Box<?>> Note that here there is a ? 请注意,这里有一个? at the top level. 在顶层。 This allows the type argument of List to be any subtype of Box<?> , which includes Box<String> , Box<Integer> . 这使List的类型参数可以是Box<?>任何子类型,包括Box<String>Box<Integer>

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

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