在Java中,它说:
String[] is subtype of Object[]
所以数组被认为是协变的。但对于仿制药他们说:
List<X> will not be subType of List<Y>.
因此它不变。但问题是,“泛型是否真的不变”?
例如,如果我给:
List<? extends Exception>
这意味着该列表可以采用Exception
的子类型,比如说这是有效的:
List<? extends Exception> k = new ArrayList<NumberFormatException>();
那么为什么泛色被认为是不变的?
答案 0 :(得分:7)
List<? extends Exception> k = new ArrayList<NumberFormatException>();
这意味着列表可以采用Exception的子类型
不完全。您可以分配到k
List
- 或其任何子类型,因为您有ArrayList
- 在这种情况下,Exception
的任何子类型1}}。
但是你不能添加到k
Exception
的任何子类型,或任何相关的任何子类型,因为k
是<{1}}的<{1}}强> List
的某个未知子类型。例如,
Exception
会出错。
检索也仅限于已知类型:
k.add(new NumberFormatException());
答案 1 :(得分:1)
数组中的数组是协变的,但它们不应该是。这只是Java语言中的许多设计缺陷之一,特别是打字系统。 请考虑以下代码:
public void messUp(Object objects[]) { objects[0] = "foo"; }
Integer ints[] = new Integer[] {1,2,3};
messUp(ints);
此编译没有警告,但在执行时抛出ArrayStoreException
。
要回答您的问题,List<T>
是不变的,因为List<String>
不是List<Object>
的子类。 &#34;延伸&#34;关键字用于约束类型参数,但不影响方差:<T> void foo(List<T>)
表示您可以将任何类型的元素列表传递给foo
,{{1除了它约束类型参数<T extends Exception> void foo(List<T>)
之外,它意味着同样的事情,因此它必须是T
的子类。
这不会使Exception
成为List<T>
的子类,它们仍然是两个不同的类。如果它是一个子类,你可以用我用上面的数组做的同样的技巧:
List<Exception>
但这不会编译,因为<T extends Exception> void foo(List<T> exceptions) {
List<Exception> l = exceptions;
l.add(new RuntimeException());
}
无法分配给List<T>
(因为它不是子类);
答案 2 :(得分:1)
我认为你问题的简单答案是语义问题
List<Object>
不是List<String>
的超类型。 Collection<String>
是其超类型,而ArrayList<String>
是其可能的子类型之一。
用另一种方式:
Object[] array = new String[2]; //is a valid declaration.
List<Object> list = new ArrayList<String>(); //is not.