【问题标题】:How a list consists of lists could be passed by value (not reference) in java method?由列表组成的列表如何在java方法中按值(而不是引用)传递?
【发布时间】:2015-01-01 03:12:27
【问题描述】:

我看到了如何通过 ArrayList 的值传递一个 ArrayList,这样被调用的方法就不会修改原始的 Arraylist。 Passing ArrayList as value only and not reference 但是,我试图传递一个本身包含其他 Arraylist 的 ArrayList;也就是Arraylist的Arraylist。

public class Test {
public static void main(String[] args){
     ArrayList<ArrayList<Integer>> lists = new ArrayList<ArrayList<Integer>>();

     for(int j=0;j<2;j++){           
         ArrayList<Integer> list=new ArrayList<Integer>();           
         for(int i=5;i>0;i--){
             list.add(i);
         }
         lists.add(list);
     }

     System.out.println("Before");
     printLists(lists);

     processLists(lists);

     System.out.println("\nAfter");
     printLists(lists);     
}   
public static void processLists(ArrayList<ArrayList<Integer>> list){

    ArrayList<ArrayList<Integer>> myTrace=new ArrayList<ArrayList<Integer>>(list);
    //myTrace.addAll(list);     
    for(int j=0;j<myTrace.size();j++){ 
        myTrace.get(j).remove(myTrace.get(j).size()-1); //remove last element in the inner lists
    }       
    System.out.println("\nInside");     
    printLists(myTrace);
}

public static void printLists(ArrayList<ArrayList<Integer>> lists){     
    for(int i=0;i<lists.size();i++){
        for(int j=0;j<lists.get(i).size();j++){
            System.out.print(lists.get(i).get(j)+" ");
        }
        System.out.println();
    }
}   
}

假设上面的代码生成输出为:

之前:5 4 3 2 1 \n 5 4 3 2 1

内部:5 4 3 2 \n 5 4 3 2

之后:5 4 3 2 \n 5 4 3 2

这里,processLists 方法正在改变“列表”的原始内容。如何限制这种修改?我已经尝试过链接中提到的解决方案。虽然它适用于单个 ArrayList,但不适用于 ArrayList 的 ArrayList。

【问题讨论】:

  • 不要将引用传递与对象可变性混淆。

标签: java arraylist pass-by-reference


【解决方案1】:

当你说

ArrayList<T> a = new ArrayList<T> (b);

它将使用来自b 的数据副本创建一个新的ArrayList。然而,虽然创建了一个新的ArrayList,但它不会复制元素所引用的对象。因此,a 的每个元素都将引用 same 对象作为b 的相应元素。

因此,特别是:

ArrayList<ArrayList<Integer>> myTrace = new ArrayList<ArrayList<Integer>>(list);

只创建一个新的ArrayList。它不会复制所有 ArrayList&lt;Integer&gt; 元素。因此,在上述之后,myTrace.get(0) == list.get(0) 将是 true,因为它们是相同的引用 [如果列表不为空]。如果你做了一些修改元素的事情,修改会同时出现在这两种情况下:

myTrace.get(n).set(x,y)

也会影响由list.get(n) 引用的ArrayList&lt;Integer&gt;,因为myTrace.get(n)list.get(n) 将返回相同的引用。

你需要一个循环来复制数组:

ArrayList<ArrayList<Integer>> myTrace = new ArrayList<ArrayList<Integer>>();
for (ArrayList<Integer> sublist : list) {
    myTrace.add(new ArrayList<Integer>(sublist));  // makes a copy of the sublist
}

或在 Java 8 中使用流:

ArrayList<ArrayList<Integer>> myTrace = new ArrayList<> (
    list.stream().map(ArrayList::new).collect(Collectors.toList()));

【讨论】:

    【解决方案2】:

    您链接到的文章说要制作并传递列表的副本,以便无法更改原始内容。在这里可以应用相同的技术,但您必须复制所有内容

    【讨论】:

    • 感谢您的建议。 ArrayList> myTrace=new ArrayList>(list);不是复制一切吗? myTrace.addAll(list);也无济于事。
    • 什么没有被复制?
    • @TanzeemBinNoor ArrayList 的元素是对其他ArrayList 的引用。当您使用该构造函数时,它将创建一个新的ArrayList,但其内容将是 same 引用作为原始引用。如果您需要所有这些列表的副本,则必须自己完成,无论是在循环中还是使用 Java 8 流。这就是你要找的东西吗?
    猜你喜欢
    • 2021-04-27
    • 2014-02-04
    • 1970-01-01
    • 1970-01-01
    • 2014-05-18
    • 2017-03-15
    • 2017-04-01
    • 1970-01-01
    • 2011-01-20
    相关资源
    最近更新 更多