为什么 List<Integer[]> listOfArrays = Arrays.asList(new Integer[]{1, 2}) 不编译?
Why List<Integer[]> listOfArrays = Arrays.asList(new Integer[]{1, 2}) doesn't compile?
1) 好的
List<int[]> listOfArrays1 = Arrays.asList( new int[]{1, 2} );
2) 好的
List<int[]> listOfArrays2 = Arrays.asList( new int[]{1, 2}, new int[]{3, 4} );
3) 编译错误Type mismatch: cannot convert from List<Integer> to List<Integer[]>
List<Integer[]> listOfArrays3 = Arrays.asList( new Integer[]{1, 2} );
4) 好的
List<Integer[]> listOfArrays4 = Arrays.asList( new Integer[]{1, 2}, new Integer[]{3, 4} );
这是 asList
的签名:public static <T> List<T> asList(T... a)
asList
需要 0 个或多个 "a" 类型的 T。我的 "a" 是 new Integer[]{1, 2}
并且它是 Integer[]
类型。那么,为什么它生成 List<Integer>
而不是 List<Integer[]>
?
我们来看问题示例(3rd):
List<Integer[]> listOfArrays3 = Arrays.asList( new Integer[]{1, 2} );
如您所示,方法签名是:
public static <T> List<T> asList(T... a)
在这种特殊情况下,T...
正在考虑单个 Integer[]
。可以向 T...
提供数组或未指定数量的相同对象。由于您指定了一个数组,因此 T
被视为 Integer
(并且 T...
变为 Integer[]
)。
当您提供 int[]
作为单个参数 (1st) 时,编译器不会自动将其包装为 Integer[]
,因为这样对象不同于 int[]
。因为 int
不是对象,所以唯一可以适合 T
的对象类型是 int[]
(它将参数构建为 int[][]
)。
提供两个 int[]
s (2nd) 更明显,因为编译器只能将 T...
的两个数组视为 int[]
s,因此 T...
也是 int[][]
.
当您提供两个 Integer[]
s (4th) 时,编译器别无选择,只能考虑构成 T...
as Integer[]
(变成一个数组:Integer[][]
)。
编辑:提供数组作为可变参数:
您可以提供单个数组作为可变参数。让我们举一个没有泛型的例子:
public int iLoveMeSomeInts(int...nums)
向此方法提供 int[]
作为参数确实有效。出于验证签名的目的,该数组被视为 int
的可变参数,然后该可变参数被视为方法内部逻辑的 int[]
。
您示例中的不同之处在于参数是 T...
。泛型 T
必须 是一个对象,因此在这种情况下编译器不能将 int[]
视为 int...
的可变参数。然后编译器别无选择,只能将 int[]
视为 int[]...
的可变参数中的单个元素(因为 int[]
是一个对象)。这一点没有歧义。
但是,因为 Integer
是 一个对象,编译器将使用单个 Integer[]
作为 Integer...
。
更酷的是:如果你想使用有问题的方法返回一个 Integer[]
,但仍然只提供一个 Integer[]
,你可以调用:
Arrays.<Integer[]>asList(new Integer[] {1, 2});
这会强制编译器将您的单个 Integer[]
视为 Integer[]...
。
1) 好的
List<int[]> listOfArrays1 = Arrays.asList( new int[]{1, 2} );
2) 好的
List<int[]> listOfArrays2 = Arrays.asList( new int[]{1, 2}, new int[]{3, 4} );
3) 编译错误Type mismatch: cannot convert from List<Integer> to List<Integer[]>
List<Integer[]> listOfArrays3 = Arrays.asList( new Integer[]{1, 2} );
4) 好的
List<Integer[]> listOfArrays4 = Arrays.asList( new Integer[]{1, 2}, new Integer[]{3, 4} );
这是 asList
的签名:public static <T> List<T> asList(T... a)
asList
需要 0 个或多个 "a" 类型的 T。我的 "a" 是 new Integer[]{1, 2}
并且它是 Integer[]
类型。那么,为什么它生成 List<Integer>
而不是 List<Integer[]>
?
我们来看问题示例(3rd):
List<Integer[]> listOfArrays3 = Arrays.asList( new Integer[]{1, 2} );
如您所示,方法签名是:
public static <T> List<T> asList(T... a)
在这种特殊情况下,T...
正在考虑单个 Integer[]
。可以向 T...
提供数组或未指定数量的相同对象。由于您指定了一个数组,因此 T
被视为 Integer
(并且 T...
变为 Integer[]
)。
当您提供 int[]
作为单个参数 (1st) 时,编译器不会自动将其包装为 Integer[]
,因为这样对象不同于 int[]
。因为 int
不是对象,所以唯一可以适合 T
的对象类型是 int[]
(它将参数构建为 int[][]
)。
提供两个 int[]
s (2nd) 更明显,因为编译器只能将 T...
的两个数组视为 int[]
s,因此 T...
也是 int[][]
.
当您提供两个 Integer[]
s (4th) 时,编译器别无选择,只能考虑构成 T...
as Integer[]
(变成一个数组:Integer[][]
)。
编辑:提供数组作为可变参数:
您可以提供单个数组作为可变参数。让我们举一个没有泛型的例子:
public int iLoveMeSomeInts(int...nums)
向此方法提供 int[]
作为参数确实有效。出于验证签名的目的,该数组被视为 int
的可变参数,然后该可变参数被视为方法内部逻辑的 int[]
。
您示例中的不同之处在于参数是 T...
。泛型 T
必须 是一个对象,因此在这种情况下编译器不能将 int[]
视为 int...
的可变参数。然后编译器别无选择,只能将 int[]
视为 int[]...
的可变参数中的单个元素(因为 int[]
是一个对象)。这一点没有歧义。
但是,因为 Integer
是 一个对象,编译器将使用单个 Integer[]
作为 Integer...
。
更酷的是:如果你想使用有问题的方法返回一个 Integer[]
,但仍然只提供一个 Integer[]
,你可以调用:
Arrays.<Integer[]>asList(new Integer[] {1, 2});
这会强制编译器将您的单个 Integer[]
视为 Integer[]...
。