ArrayList<? extends A> array = new ArrayList<A>();
array.add(new A());
Run Code Online (Sandbox Code Playgroud)
为什么这不编译?
Java 教程的相关部分(http://docs.oracle.com/javase/tutorial/java/generics/wildcardGuidelines.html):
List 定义的列表可以非正式地认为是只读的,但这并不是严格的保证。假设您有以下两个类:
Run Code Online (Sandbox Code Playgroud)class NaturalNumber { private int i; public NaturalNumber(int i) { this.i = i; } // ... } class EvenNumber extends NaturalNumber { public EvenNumber(int i) { super(i); } // ... }考虑以下代码:
Run Code Online (Sandbox Code Playgroud)List<EvenNumber> le = new ArrayList<>(); List<? extends NaturalNumber> ln = le; ln.add(new NaturalNumber(35)); // compile-time error因为
List<EvenNumber>是 的子类型List<? extends NaturalNumber>,您可以将 le 分配给 ln。但是您不能使用 ln 将自然数添加到偶数列表中。可以对列表进行以下操作:
- 您可以添加空值。
- 你可以调用clear。
- 您可以获取迭代器并调用remove。
- 您可以捕获通配符并写入从列表中读取的元素。
您可以看到 List 定义的列表不是严格意义上的只读,但您可能会这样认为,因为您无法在列表中存储新元素或更改现有元素。
另一个相关的解释可以在这里找到(他的链接也解释了通配符的问题 - http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html):
...
但是,向其中添加任意对象是不安全的:
Run Code Online (Sandbox Code Playgroud)Collection<?> c = new ArrayList<String>(); c.add(new Object()); // Compile time error因为我们不知道 c 的元素类型代表什么,所以我们不能向它添加对象。add() 方法接受类型为 E 的参数,即集合的元素类型。当实际类型参数为 ? 时,它代表某种未知类型。我们传递给 add 的任何参数都必须是这种未知类型的子类型。因为我们不知道那是什么类型,所以我们不能传入任何东西。唯一的例外是 null,它是所有类型的成员。
另一方面,给定一个 List,我们可以调用 get() 并使用结果。结果类型是未知类型,但我们始终知道它是一个对象。因此,将 get() 的结果分配给类型为 Object 的变量或将其作为参数传递给类型为 Object 的参数是安全的。
| 归档时间: |
|
| 查看次数: |
2549 次 |
| 最近记录: |