为什么 List<Integer[]> listOfArrays = Arrays.asList(new Integer[]{1, 2}) 不能编译?

5

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) 编译错误 类型不匹配:无法从List<Integer>转换为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或多个T类型的参数"a"。我的"a"是new Integer[]{1, 2},类型为Integer[]。那么,为什么它生成的是一个List<Integer>而不是一个List<Integer[]>呢?

请解释一下为什么1和2没有显示任何错误。List不能与原始的int类型一起使用。 - Sufian
2
@Sufian int[] 不是原始类型,而是一个对象。 - RaminS
之所以能够正确解析是因为 T 可以是 int[],但不能是 int。相关信息请参考 https://dev59.com/onE85IYBdhLWcg3wikO-。 - blgt
OP,我建议您阅读这里标记的重复问题链中的答案,并确定它们是否令人满意(我认为它们不是)。如果不是,请编辑您的问题并在顶部解释为什么您认为这不是重复。也许那时候标记就会被移除。 - Zircon
1个回答

3

接下来我们看一个问题示例(第三个)

List<Integer[]> listOfArrays3 = Arrays.asList( new Integer[]{1, 2} );

如您所示,该方法的签名为:

public static <T> List<T> asList(T... a)

在这种情况下,单个Integer[]被视为T...的参数。可以提供一个数组或未指定数量的相同对象作为T...的参数。由于你指定了一个数组,因此T被视为Integer(并且T...变成了Integer[])。
当你将int[]作为单个参数(第一种情况)提供时,编译器不会自动将其包装为Integer[],因为这样的对象与int[]不同。由于int不是对象,因此唯一适合T的对象类型是int[](构建参数为int[][])。
提供两个int[](第二种情况)更加明显,因为编译器只能将两个数组视为int[],因此T...也是int[][]
当你提供两个Integer[](第四种情况)时,编译器再次更加明显,它必须将组成T...的两个参数都视为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[]...


我想我并不真正知道可变参数是如何工作的。 - Gustavo
1
Varargs 很棒,因为你可以提供任意数量的相同对象,而在方法本身中该参数将被视为数组。需要注意的是,泛型 T 必须是一个对象,因此提供一个 int[] 将不算作 int 的可变参数。 - Zircon
接近了,但它根本不含糊。您可以为可变参数提供单个数组。我将在编辑答案时为您澄清这一点。 - Zircon
然而,因为Integer是一个对象,编译器将使用一个Integer[]作为Integer...。这似乎相当武断(也许“模棱两可”不是正确的词)。Java设计人员本来也可以决定将其视为Integer[]...,对吧? - RaminS
1
他们本来可以这样做,但这样做有点自我打击。将单个数组作为可变参数传递非常方便。如果您有一个完整准备好的Integer[]想要作为Integer...传递,那么获取每个元素并将它们作为单独的参数传递会更加复杂(也不太直观)。相比之下,如果您有一个单独的Integer[]想要作为Integer[]...传递,您可以通过我展示的语句强制执行它,或者如果您不知道它,将参数作为new Integer[][] { myIntegerArray }传递。 - Zircon
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接