构造函数方法(推荐用于浅拷贝)
这是最直接、最常用的方法,用于创建一个与原列表内容相同的新列表。

语法
ArrayList<NewType> newList = new ArrayList<>(originalList);
示例
import java.util.ArrayList;
public class ArrayListCopyExample {
public static void main(String[] args) {
ArrayList<String> originalList = new ArrayList<>();
originalList.add("Apple");
originalList.add("Banana");
originalList.add("Orange");
// 使用构造函数创建一个新的 ArrayList
ArrayList<String> copiedList = new ArrayList<>(originalList);
System.out.println("Original List: " + originalList);
System.out.println("Copied List: " + copiedList);
// 修改原列表
originalList.add("Grape");
System.out.println("\nAfter adding 'Grape' to originalList:");
System.out.println("Original List: " + originalList);
System.out.println("Copied List: " + copiedList); // copiedList 不受影响
// 修改 copiedList 中的元素
copiedList.set(0, "Pineapple");
System.out.println("\nAfter setting index 0 to 'Pineapple' in copiedList:");
System.out.println("Original List: " + originalList); // originalList 不受影响
System.out.println("Copied List: " + copiedList);
}
}
输出
Original List: [Apple, Banana, Orange]
Copied List: [Apple, Banana, Orange]
After adding 'Grape' to originalList:
Original List: [Apple, Banana, Orange, Grape]
Copied List: [Apple, Banana, Orange]
After setting index 0 to 'Pineapple' in copiedList:
Original List: [Apple, Banana, Orange, Grape]
Copied List: [Pineapple, Banana, Orange]
特点
- 浅拷贝:这是最关键的一点,新列表
copiedList会复制原列表originalList中的所有引用,而不是对象本身。 - 独立的列表容器:
copiedList和originalList是两个完全独立的ArrayList对象,你向其中一个添加或删除元素,不会影响另一个。 - 共享元素:如果列表中的元素是可变对象(如
StringBuilder, 自定义类的实例),那么修改其中一个列表中的对象,会影响到另一个列表中对应的对象。 - 性能:时间复杂度为 O(n),n 是原列表的大小,因为它需要遍历并复制所有引用。
clone() 方法
ArrayList 实现了 Cloneable 接口,所以可以使用 clone() 方法。
示例
import java.util.ArrayList;
public class ArrayListCloneExample {
public static void main(String[] args) {
ArrayList<String> originalList = new ArrayList<>();
originalList.add("Apple");
originalList.add("Banana");
// 使用 clone() 方法
ArrayList<String> copiedList = (ArrayList<String>) originalList.clone();
System.out.println("Original List: " + originalList);
System.out.println("Copied List: " + copiedList);
}
}
特点
- 浅拷贝:与构造函数方法完全一样,它也是进行浅拷贝。
- 返回类型:
clone()方法的返回类型是Object,所以必须进行强制类型转换,这可能会带来一些麻烦(比如如果类型不匹配会抛出ClassCastException)。 - 不推荐:在 Effective Java 等权威著作中,通常不推荐使用
clone()方法,因为它可能会被错误地实现,其行为有时不符合预期,使用构造函数是更清晰、更安全的选择。
Java 8+ Stream API
如果你需要对列表进行转换或过滤后再复制,Stream API 是一个非常强大的工具。
语法
ArrayList<NewType> newList = originalList.stream()
.collect(Collectors.toCollection(ArrayList::new));
示例
import java.util.ArrayList;
import java.util.stream.Collectors;
public class ArrayListStreamExample {
public static void main(String[] args) {
ArrayList<Integer> originalList = new ArrayList<>();
originalList.add(1);
originalList.add(2);
originalList.add(3);
// 使用 Stream API 复制,并可以对元素进行转换
ArrayList<String> copiedList = originalList.stream()
.map(String::valueOf) // 将 Integer 转换为 String
.collect(Collectors.toCollection(ArrayList::new));
System.out.println("Original List: " + originalList);
System.out.println("Copied List (as Strings): " + copiedList);
}
}
特点
- 浅拷贝:Stream API 的底层操作同样是复制引用。
- 灵活性:最大的优点在于可以在复制的同时对元素进行处理,如
map,filter,sorted等。 - 性能:对于简单的复制,性能可能略逊于构造函数,因为它涉及流管道的开销,但对于复杂的转换操作,这是最优雅的方式。
addAll() 方法
这个方法不是直接创建一个新列表,而是将原列表的所有元素添加到一个已存在的列表中。
示例
import java.util.ArrayList;
public class ArrayListAddAllExample {
public static void main(String[] args) {
ArrayList<String> originalList = new ArrayList<>();
originalList.add("Apple");
originalList.add("Banana");
// 创建一个空的新列表
ArrayList<String> copiedList = new ArrayList<>();
// 将原列表的所有元素添加到新列表中
copiedList.addAll(originalList);
System.out.println("Original List: " + originalList);
System.out.println("Copied List: " + copiedList);
}
}
特点
- 浅拷贝:同样是浅拷贝。
- 需要预先存在目标列表:你必须先创建一个新的
ArrayList实例,然后才能调用addAll。 - 适用场景:当你已经有一个列表,并希望将另一个列表的内容追加到它时,这个方法很合适,但如果只是为了复制,不如构造函数简洁。
深拷贝 vs. 浅拷贝
前面介绍的所有方法都是浅拷贝,理解浅拷贝和深拷贝的区别至关重要。

浅拷贝
-
行为:复制列表的容器(
ArrayList对象本身),但列表中的元素仍然是原列表元素的引用。 -
影响:
- 对列表本身的修改(如
add,remove)不会影响另一个列表。 - 对列表中可变对象的修改会同时影响两个列表。
- 对列表本身的修改(如
-
示例:
class Person { String name; Person(String name) { this.name = name; } @Override public String toString() { return name; } } ArrayList<Person> list1 = new ArrayList<>(); list1.add(new Person("Alice")); ArrayList<Person> list2 = new ArrayList<>(list1); // 浅拷贝 list1.get(0).name = "Bob"; // 修改 list1 中的对象 System.out.println(list1.get(0)); // 输出: Bob System.out.println(list2.get(0)); // 输出: Bob (也被修改了!)
深拷贝
-
行为:不仅复制列表的容器,还复制列表中的每一个元素,创建全新的对象。
(图片来源网络,侵删) -
影响:两个列表完全独立,互不影响。
-
如何实现:Java 没有内置的深拷贝方法,你需要手动实现。
-
方法1:序列化与反序列化(通用但较慢)
import java.io.*; public class DeepCopyUtil { @SuppressWarnings("unchecked") public static <T extends Serializable> ArrayList<T> deepCopy(ArrayList<T> originalList) { try { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(originalList); oos.flush(); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return (ArrayList<T>) ois.readObject(); } catch (IOException | ClassNotFoundException e) { throw new RuntimeException("Failed to deep copy the list", e); } } }注意:列表中的所有元素类都必须实现
Serializable接口。 -
方法2:手动创建并复制(推荐,更高效、更安全)
// 假设 Person 类有一个拷贝构造函数 // class Person { ... public Person(Person other) { this.name = other.name; } } ArrayList<Person> list1 = new ArrayList<>(); list1.add(new Person("Alice")); ArrayList<Person> list2 = new ArrayList<>(); for (Person p : list1) { list2.add(new Person(p)); // 使用拷贝构造函数创建新对象 } list1.get(0).name = "Bob"; System.out.println(list1.get(0)); // 输出: Bob System.out.println(list2.get(0)); // 输出: Alice (未被修改)
-
总结与最佳实践
| 方法 | 类型 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
构造函数 new ArrayList<>(original) |
浅拷贝 | 最简洁、最安全、性能好 | 无法在复制时转换元素 | 日常浅拷贝的首选方法 |
clone() |
浅拷贝 | 语法看起来简单 | 需要强制类型转换,不推荐使用 | 应尽量避免 |
| Stream API | 浅拷贝 | 灵活,可同时进行转换 | 代码稍长,简单拷贝性能略低 | 需要对元素进行转换或过滤时 |
addAll() |
浅拷贝 | 直观 | 需要先创建目标列表 | 向已存在的列表追加内容时 |
| 手动深拷贝 | 深拷贝 | 完全独立,安全可控 | 实现复杂,需要元素类支持 | 当列表包含可变对象且需要完全隔离时 |
核心建议:
-
如果只是想复制一个
ArrayList并且不关心元素是否被共享(即浅拷贝),请始终使用构造函数:ArrayList<String> copy = new ArrayList<>(original);
-
如果你的列表包含可变对象(如
Date, 自定义类实例),并且你需要两个列表完全独立,那么你必须实现深拷贝。 手动为每个元素实现拷贝逻辑(如拷贝构造函数或clone()方法)是最佳实践。 -
如果需要在复制的同时对元素进行转换,请使用 Stream API。
