Collections.nCopies不创建列表的副本

时间:2015-07-14 17:40:17

标签: java arraylist

我创建了一个List列表,其默认大小已设置。因此,我使用set方法将数据添加到列表中。

我的代码:

package test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Test2 {
public static void main(String args[]) {
    List<List<String>> keys = new ArrayList<>(Collections.nCopies(3, new ArrayList<>()));
    List<String> values = keys.get(2);
    values.add("Hello");
    values.add("One Two");
    keys.set(2, values);
    List<String> tempList = keys.get(1);
    tempList.add("Now adding at 1");
    keys.set(1, tempList);
    System.out.println("Position 1 " + keys.get(1).toString());
    System.out.println("Position 2 " + keys.get(2).toString());
}
}

我的输出:

Position 1 [Hello, One Two, Now adding at 1]
Position 2 [Hello, One Two, Now adding at 1]

为什么这样做?第一个数据也会附加到第二个数据上吗?我做错了什么?

1 个答案:

答案 0 :(得分:12)

List<List<String>> keys = new ArrayList<>(Collections.nCopies(3, new ArrayList<>()))

在此声明中,它不会创建ArrayList<>的三个新实例。它创建一个实例,并创建一个列表,其中包含对相同实例的三个引用。因此,列表列表中的每个位置都是对同一ArrayList实例的引用。

你可以做的最简单的事情是使用for循环:

for(int i = 0; i < numCopies; i++) {
    keys.add(new ArrayList<>());
}

使用Java 8的流API的等效解决方案:

IntStream.range(0, n).mapToObj(ArrayList<String>::new).forEach(keys::add);

或者您可以像这样一次创建keys

List<List<String>> keys = IntStream.range(0, numCopies)
                                   .mapToObj(ArrayList<String>::new)
                                   .collect(Collectors.toList());