Java中List赋值给另一个List的6种方法详解

今日在开发ANDROD应用时,在用到LIST 类对象赋值时突然想到了深拷贝与浅拷贝的问题,在此复习一下,在Java开发中,List集合的复制是高频操作场景。错误的使用方式可能导致数据意外修改或性能问题。本文深度解析6种实现方式,并给出生产环境最佳实践建议。


一、基础赋值方式对比

1. 直接赋值(引用传递)

List listA = new ArrayList<>(Arrays.asList("A", "B"));
List listB = listA; // 直接赋值

listB.add("C");
System.out.println(listA); // 输出[A, B, C]

优点:

  • 零开销的赋值操作
  • 适合需要同步修改的场景

缺点:

  • 两个List指向同一内存地址
  • 任意修改都会影响另一个List

2. 构造函数复制(浅拷贝)

List listB = new ArrayList<>(listA);

优点:

  • 创建独立容器对象
  • 线程安全的基础操作

缺点:

  • 元素仍是引用传递
  • 修改元素对象属性会影响两个List

3. addAll方法(批量添加)

List listB = new ArrayList<>();
listB.addAll(listA);

优点:

  • 支持跨List类型复制
  • 可追加到已有集合

缺点:

  • 需要先初始化目标集合
  • 同样存在浅拷贝问题

二、高级复制方案

4. Stream API(Java8+)

List listB = listA.stream()
                         .collect(Collectors.toList());

优点:

  • 函数式编程风格
  • 方便进行中间过滤/转换操作

缺点:

  • 需要Java8+环境
  • 性能略低于直接复制

5. Apache Commons工具类

// 浅拷贝
List listB = new ArrayList<>(listA); 

// 深拷贝(需要实现序列化)
List deepCopy = SerializationUtils.clone(listA);

优点:

  • 提供现成的深拷贝方案
  • 简化开发代码量

缺点:

  • 引入第三方依赖
  • 序列化有性能损耗

6. 序列化深拷贝(完全独立)

public static  List deepCopy(List src) {
    try {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(src);
        
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return (List) ois.readObject();
    } catch (Exception e) {
        throw new RuntimeException("深拷贝失败", e);
    }
}

优点:

  • 完全独立的副本
  • 元素级深拷贝

缺点:

  • 所有元素必须实现Serializable
  • 性能开销最大

三、生产环境选型建议

场景需求

推荐方案

性能

安全性

快速同步修改

直接赋值

★★★

基础容器隔离

构造函数复制

★★★

★★

追加到现有集合

addAll方法

★★★

★★

带数据转换的复制

Stream API

★★

★★★

需要深拷贝的复杂对象

序列化方案

★★★★

快速实现深拷贝

Apache Commons

★★

★★★★


四、关键注意事项

  1. 元素不可变性:当元素为String、Integer等不可变对象时,浅拷贝即安全
  2. 并发修改:使用Collections.synchronizedList()包装保证线程安全
  3. 巨型集合处理:超过10万条数据时慎用深拷贝
  4. 防御性编程:对外返回集合时优先返回不可修改副本

五、高频问题解答

Q:如何判断是否需要深拷贝?
A:当List中的元素是可变对象(如自定义实体类),且需要完全隔离修改时使用深拷贝。

Q:为什么推荐使用构造函数而不是clone()?
A:clone()方法存在设计缺陷,ArrayList等具体实现类可能不支持,且容易抛出
CloneNotSupportedException

Q:Java10有什么新特性?
A:可以使用List.copyOf()工厂方法:

List listB = List.copyOf(listA);

掌握这些List复制技巧,可以避免80%的集合操作Bug。根据具体场景选择最适合的方案,才能写出既高效又安全的代码!建议收藏本文作为开发手册随时查阅。

相关文章

c语言函数中如何给一个字符串数组赋值?

1.打开Visual C++ 6.0,新建一个C++ source file源文件;2.输入以下代码: #include "stdio.h" #include ";3.代码关键部分,见图红色部分,第一...

.ArrayList源码三:数组扩容以及元素拷贝

数组扩容以及元素拷贝 这个 ArrayList 动态性的核心机制。ArrayList 源码三:数组扩容以及元素拷贝在之前的文章中,我们已经了解到 ArrayList 底层是基于数组 elementDa...

系列专栏(六):解构赋值

ES6作为新一代JavaScript标准,已正式与广大前端开发者见面。为了让大家对ES6的诸多新特性有更深入的了解,Mozilla Web开发者博客推出了《ES6 In Depth》系列文章。CSDN...

数组结构分为一维数组二维数组一维数组赋值使用

数组结构数组是最为常见的一种数据结构,不是基本数据类型是对象,是相同类型的用一个标识符封装到一起的基本类型数据序列组成一个对象。可以用一个统一的数组名和下标来确定数组中的元素。数组包括一维数组和二维数...

第二章 数组 2.1 数组的声明、赋值及读取

第二章 数组2.1 数组的声明、赋值及读取数组,就是多个数据或变量的集合。数组分为一维数组、二维数组、三维数组......等等。通常我们使用的是一维数组和二维数组。数组是先声明,后使用。1、声明数组数...

VBA一组代码如何搞定赋值给数组arr及回填数据给...

VBA++ 题记:一剪闲云一溪月,一程山水一年华。一世浮生一刹那,一树菩提一烟霞。岁月静好,现世安稳。纵算云水漂泊,心若安宁,亦可淡若清风。希望见者与不见者都能安康。静下心,多学习有用的知识,多提高自...