为什么说仿制药在"?时是不变的?延伸Klass"被允许?

时间:2015-01-15 15:54:47

标签: java generics

在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>();

那么为什么泛色被认为是不变的?

3 个答案:

答案 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.