有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何从旧的ArrayList<ArrayList<Integer>>创建新的ArrayList而不更改旧的?

我有一个ArrayList<ArrayList<Integer>> res,它包含一些整数子集。这些子集的一部分我保存在ArrayList<ArrayList<Integer>> prev。例如res = [[1], [1, 2], [2]]prev = [[1, 2], [2]]。然后我想创建新的ArrayList<ArrayList<Integer>> tmp,它是prev的副本,在tmp的每个子集中添加新元素,而不改变prev,然后将tmp添加到结果中。我使用的代码如下所示:

ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();
  ArrayList<ArrayList<Integer>> prev = new ArrayList<ArrayList<Integer>>();
  for (int i = 0; i < S.length; i++) {
    ArrayList<ArrayList<Integer>> tmp = new ArrayList<ArrayList<Integer>>();
    if(something){
      tmp = new ArrayList<ArrayList<Integer>>(prev);
      for(ArrayList<Integer> a: tmp){
        a.add(S[i]);
      }
      res.addAll(tmp);
      prev = new ArrayList<ArrayList<Integer>>(tmp);
}

因此,如果res = [[1], [1, 2], [2]]prev = [[1, 2], [2]]{},我希望tmp变成[[1, 2, 2], [2, 2]],然后将tmp添加到res。问题是,当我向tmp添加元素时,我也会更改prev,我也会更改res,这是我不想要的。因此,在上面的迭代之后,我的res包含[[1], [1, 2, 2], [2, 2], [1, 2, 2], [2, 2]],而不是[[1], [1, 2], [2], [1, 2, 2], [2, 2]]。我试着用tmp.addAll(prev);更改这一行tmp = new ArrayList<ArrayList<Integer>>(prev);,但它没有再起作用。我的错在哪里

编辑:

我想我解决了这个问题——我把tmp = new ArrayList<ArrayList<Integer>>(prev);行改为

for(ArrayList<Integer> a: prev){
    tmp.add(new ArrayList<Integer>(a));
}

然而,我仍然需要解释一下为什么这样做有效,以及为什么之前的方法不起作用


共 (2) 个答案

  1. # 1 楼答案

    问题是您正在更改原始列表值(通过引用传递) 我认为你必须使用clone()来避免副作用

    代码应该是这样的:

      ArrayList<ArrayList<Integer>> prev = new ArrayList<ArrayList<Integer>>();
          for (int i = 0; i < SCloned.length; i++) {
        ArrayList<ArrayList<Integer>> SCloned = (ArrayList<ArrayList<Integer>>)S.clone();
            ArrayList<ArrayList<Integer>> tmp = new ArrayList<ArrayList<Integer>>();
    

    然后做a.add(SCloned[i]);未经测试

  2. # 2 楼答案

    tmp = new ArrayList<ArrayList<Integer>>(prev)
    

    这将创建一个副本,它是一个新的顶级ArrayList,包含与原始版本相同的引用。tmp的成员是对仍然在prev中的完全相同对象的引用

    你需要对整个结构进行深度复制,这是你通过编辑完成的

    注意Integer对象是不可变的。因此,可以从多个地方引用它们,因此它们不需要重复