Java中修改子ArrayList为何会同步到原列表?如何避免该问题?
// "static void main" must be defined in a public class. import java.util.*; public class Main { static void func(ArrayList<ArrayList<Integer>> arr) { ArrayList<Integer> arr1 = new ArrayList(); arr1.add(0); arr.add(arr1); arr1.set(0,5); } public static void main(String[] args) { ArrayList<ArrayList<Integer>> arr = new ArrayList<ArrayList<Integer>>(); func(arr); for(int i=0;i<arr.size();i++) { for(int j=0;j<arr.get(i).size();j++) { System.out.print(arr.get(i).get(j)); } System.out.println(); } } }
问题解答
同步变更的原因
Java中ArrayList属于引用类型,执行arr.add(arr1)操作时,并没有把arr1的完整内容复制一份存入二维列表,只是把arr1指向的堆内存地址的引用存入了arr。
也就是说*arr1和arr中存储的第一个元素,指向的是堆内存中同一个ArrayList对象*,通过任意一个引用修改这个对象的内容,另一个引用访问到的自然是修改后的结果。
避免方案
往二维ArrayList中添加一维列表时,不要直接传入原对象的引用,传入原一维列表的副本即可。
当前场景下一维列表的元素是不可变的Integer类型,仅做浅拷贝就足够,修改添加逻辑为:
// 调用ArrayList的拷贝构造函数生成arr1的副本,存入arr arr.add(new ArrayList<>(arr1));
如果后续一维列表存储的是自定义可变对象,还需要对每个元素做深拷贝,才能完全隔离原对象和副本的修改影响。
内容的提问来源于stack exchange,提问作者Vinayak Anil
相关产品推荐
相关产品推荐

