如何将int[]数组转换为List?

20
我原本期望这段代码会显示true:
int[] array = {1, 2};
System.out.println(Arrays.asList(array).contains(1));

这是将数组转换为列表的方法。只需记住列表是不可变的。尝试输出列表的内容,您会看到它包含1和2的值。 - Shervin Asgari
1
@Shervin:自己试一下就会发现它不行。 - Michael Borgwardt
12个回答

37

当泛型被擦除并且可变参数被转换时,方法 Arrays.asList(T ...) 实际上等同于类型为 Arrays.ofList(Object[]) 的方法(它是同一方法的二进制等效物,JDK 1.4 版本)。

原始类型数组是一个 Object(参见 this question),但不是一个 Object[],因此编译器认为您正在使用可变参数版本,并在您的 int 数组周围生成一个 Object 数组。您可以通过添加额外的步骤来说明发生了什么:

int[] array = {1, 2};
List<int[]> listOfArrays = Arrays.asList(array);
System.out.println(listOfArrays.contains(1));

这段代码可以编译通过,和你的代码等价。但是它显然会返回 false。

编译器将 varargs 调用转换为带有单个数组的调用,因此使用参数 T t1, T t2, T t3 调用期望参数为 T ... 的 varargs 方法等同于使用 new T[]{t1, t2, t3} 进行调用。但是特殊情况是,如果方法需要一个对象数组,那么原始类型的 varargs 将在创建数组之前自动装箱。因此,编译器认为 int 数组被传递为单个 Object,并创建一个元素类型为 Object[] 的单元素数组,将其传递给 asList()

所以这里再次展示上面的代码,展示编译器内部的实现方式:

int[] array = {1, 2};
// no generics because of type erasure
List listOfArrays = Arrays.asList(new Object[]{array});
System.out.println(listOfArrays.contains(1));

以下是使用int值调用Arrays.asList()的好坏方式:

// These versions use autoboxing (which is potentially evil),
// but they are simple and readable

// ints are boxed to Integers, then wrapped in an Object[]
List<Integer> good1 = Arrays.asList(1,2,3);
// here we create an Integer[] array, and fill it with boxed ints
List<Integer> good2 = Arrays.asList(new Integer[]{1,2,3});

// These versions don't use autoboxing,
// but they are very verbose and not at all readable:

// this is awful, don't use Integer constructors
List<Integer> ugly1 = Arrays.asList(
    new Integer(1),new Integer(2),new Integer(3)
);
// this is slightly better (it uses the cached pool of Integers),
// but it's still much too verbose
List<Integer> ugly2 = Arrays.asList(
    Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3)
);

// And these versions produce compile errors:
// compile error, type is List<int[]>
List<Integer> bad1 = Arrays.asList(new int[]{1,2,3});
// compile error, type is List<Object>
List<Integer> bad2 = Arrays.asList(new Object[]{1,2,3});

参考资料:


但是,为了以简单的方式解决您的问题:

在Apache Commons / Lang(请参见Bozho's answer)和Google Guava中有一些库解决方案:


Integer[] 也是一个对象。 - aioobe
我知道,但它也是一个 Object[],这更匹配。 - Sean Patrick Floyd
哎呀,那刺痛却带着一种甜蜜的痛感。 - Suraj Chandran
int[] 不能被强制转换为 Object[](参见这个问题),但可以转换为 Object。 - Lucas Hoepner

15

Arrays.asList(array)将会得到一个 int[] 的单例列表。

如果你将 int[] 改成 Integer[],它会如你所期望的工作。不知道这是否对您有帮助。


5
Arrays.asList(ArrayUtils.toObjectArray(array))

(ArrayUtils 来自 commons-lang)

但是,如果您只想调用 contains ,则不需要这样做。只需使用 Arrays.binarySearch(..) (首先对数组进行排序)。


1
也许我们可以补充说明ArrayUtils是Apache Commons的一部分:http://commons.apache.org/ - Nicolas
5
对不起,我无法理解时间旅行。 - Nicolas
现在是:Arrays.asList(ArrayUtils.toObject(array)); - Claes Mogren

1

这个

System.out.println(Arrays.asList(array).contains(array));

返回true


1

看起来你对 Arrays.asList(T... a) 的理解是错误的。你不会是第一个对它的工作方式做出假设的人。

试着用它:

System.out.println(Arrays.asList(1, 2).contains(1));

1

自动装箱在这种情况下并不按照您的期望工作。以下代码可能有点冗长,但可以将int数组转换为列表:

List<Integer> list = new ArrayList<Integer>(array.length);
for (int value : array) {
    list.add(value);
}

1
以下代码显示为 true:
Integer[] array = {1, 2};
System.out.println(Arrays.asList(array).contains(1));

你的版本失败了,因为Int不是对象,但Int[]是一个对象。因此,你将使用一个元素作为Collection调用asList(T... a),因为不可能有一个Collection a。


1
如何将int[]数组转换为List?
使用现代Java特性直接回答:
int[] array = {1, 2};
List<Integer> list = IntStream.of(array).boxed().toList();
System.out.println(list.contains(1)); // true

注意:`toList()` 自 Java 16 版本开始可用。
自 Java 8 开始的另一种选择是 `collect(Collectors.toList())`。

但请注意,Stream.toList() 返回的列表是不可变的。 - user16320675

0
如果您只想检查数组是否包含某个元素,只需迭代数组并搜索该元素即可。这将需要o(n/2)的时间。所有其他解决方案都不够有效。任何将数组复制到列表的方法都必须迭代数组,因此此操作仅需要n个原子赋值。

任何将数组复制到列表的方法都必须遍历数组。这并不正确。Arrays.asList()使用提供的数组来支持列表,因此只有在搜索时才会迭代,就像您所建议的那样。 - Sean Patrick Floyd

0

当你调用时

Arrays.asList(array)

在您的原始类型数组上,您获得了一个包含一个对象的List实例:int值的数组!您必须首先将原始类型数组转换为对象数组,正如@Bozho在他的答案中建议的那样。

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