如何避免多维ArrayList修改时影响另一个ArrayList
二维ArrayList深拷贝:修改l2不影响l1
我有两个完全相同的二维ArrayList(
ArrayList<ArrayList<Integer>>)l1和l2。创建并填充l1后,用new ArrayList<>(l1)初始化l2。一维场景下修改l2不会影响l1,但多维场景中,给l2的子列表添加新Integer时l1也会被修改,不过给l2添加新的ArrayList时l1不受影响。请问如何确保修改l2中的元素不会影响l1?示例代码:
ArrayList<ArrayList<Integer>> l1 = new ArrayList<>(); for (var x = 0; x < 10; x++) { l1.add(new ArrayList<>()); for (var y = 0; y < 10; y++) { l1.get(x).add(y); } } ArrayList<ArrayList<Integer>> l2 = new ArrayList<ArrayList<Integer>>(l1); // 希望此操作不改变l1 l2.get(0).add(999);
问题根源:浅拷贝的局限性
new ArrayList<>(l1)属于浅拷贝:它仅复制了外层ArrayList的结构(即子列表的引用集合),但内部的每个子ArrayList<Integer>仍与l1共享同一对象。因此修改l2子列表的元素时,本质是操作和l1相同的子列表对象,会同步影响l1;而给l2添加新子列表时,只是给外层列表新增独立引用,不会触动l1的外层结构,所以l1不受影响。
解决方法:实现深拷贝
要让l2与l1完全独立,需对每个子列表也进行拷贝(即深拷贝),以下是几种常用实现方式:
1. 手动循环拷贝(直观易懂)
遍历外层列表,为每个子列表创建新的ArrayList并复制元素:
ArrayList<ArrayList<Integer>> l2 = new ArrayList<>(); for (ArrayList<Integer> subList : l1) { // 复制子列表到新的ArrayList实例 l2.add(new ArrayList<>(subList)); }
2. Java 8+ Stream简化写法
借助Stream API简化深拷贝代码:
import java.util.stream.Collectors; // ... ArrayList<ArrayList<Integer>> l2 = l1.stream() .map(ArrayList::new) // 对每个子列表生成新拷贝 .collect(Collectors.toCollection(ArrayList::new));
3. 第三方工具类简化(可选)
如果项目引入了Apache Commons Collections或Guava,可利用工具类进一步简化:
- Apache Commons Collections:
import org.apache.commons.collections4.ListUtils; import java.util.stream.Collectors; // ... ArrayList<ArrayList<Integer>> l2 = ListUtils.emptyIfNull(l1) .stream() .map(subList -> new ArrayList<>(ListUtils.copy(subList))) .collect(Collectors.toCollection(ArrayList::new));
- Guava:
import com.google.common.collect.Lists; // ... ArrayList<ArrayList<Integer>> l2 = Lists.newArrayList( l1.stream().map(Lists::newArrayList).iterator() );
完成深拷贝后,执行l2.get(0).add(999)只会修改l2的子列表,l1的对应子列表不会产生任何变化,实现了两者的完全独立。
内容的提问来源于stack exchange,提问作者Gamaray
相关产品推荐
相关产品推荐

