Java中集合的深拷贝与浅拷贝实现
在Java中,集合的拷贝分为浅拷贝(shallow copy)和深拷贝(deep copy),理解它们的区别及实现方式非常重要。
浅拷贝(Shallow Copy)
浅拷贝只复制集合本身,而不复制集合中的元素。新集合和原集合共享相同的元素引用。
实现方式
使用构造函数
List<String> original = new ArrayList<>(); original.add("A"); original.add("B"); List<String> shallowCopy = new ArrayList<>(original);
使用addAll方法
List<String> shallowCopy = new ArrayList<>(); shallowCopy.addAll(original);
使用clone方法
List<String> shallowCopy = (List<String>) original.clone();
Java 8+ Stream API
List<String> shallowCopy = original.stream().collect(Collectors.toList());
深拷贝(Deep Copy)
深拷贝不仅复制集合本身,还会递归复制集合中的所有元素。新集合和原集合拥有完全独立的对象。
实现方式
手动复制元素
List<Person> original = new ArrayList<>(); original.add(new Person("Alice")); List<Person> deepCopy = new ArrayList<>(); for (Person p : original) { deepCopy.add(new Person(p.getName())); // 假设Person有拷贝构造函数 }
使用序列化(Serialization)
import java.io.*; public static <T> List<T> deepCopy(List<T> src) throws IOException, ClassNotFoundException { ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(byteOut); out.writeObject(src); ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray()); ObjectInputStream in = new ObjectInputStream(byteIn); @SuppressWarnings("unchecked") List<T> dest = (List<T>) in.readObject(); return dest; }
使用第三方库
- Apache Commons Lang的SerializationUtils
List<Person> deepCopy = SerializationUtils.clone(original);
- Gson库
Gson gson = new Gson(); String json = gson.toJson(original); List<Person> deepCopy = gson.fromJson(json, new TypeToken<List<Person>>(){}.getType());
- Apache Commons Lang的SerializationUtils
Java 8+ Stream API实现深拷贝
List<Person> deepCopy = original.stream() .map(p -> new Person(p.getName())) // 假设Person有拷贝构造函数 .collect(Collectors.toList());
注意事项
- 深拷贝要求集合中的元素必须实现
Serializable
接口(如果使用序列化方式) - 对于复杂对象图,深拷贝可能更复杂,需要考虑循环引用等问题
- 深拷贝通常比浅拷贝更消耗资源
- 对于不可变对象(如String),浅拷贝和深拷贝效果相同
示例代码
import java.util.*;
import java.io.*;
import org.apache.commons.lang3.SerializationUtils;
class Person implements Serializable {
private String name;
public Person(String name) { this.name = name; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
// 拷贝构造函数
public Person(Person other) {
this.name = other.name;
}
}
public class CollectionCopyExample {
public static void main(String[] args) throws Exception {
// 浅拷贝示例
List<Person> original = new ArrayList<>();
original.add(new Person("Alice"));
List<Person> shallowCopy = new ArrayList<>(original);
shallowCopy.get(0).setName("Bob");
System.out.println(original.get(0).getName()); // 输出 "Bob" - 浅拷贝共享引用
// 深拷贝示例1 - 手动复制
List<Person> deepCopy1 = new ArrayList<>();
for (Person p : original) {
deepCopy1.add(new Person(p));
}
deepCopy1.get(0).setName("Charlie");
System.out.println(original.get(0).getName()); // 输出 "Bob" - 深拷贝不改变原对象
// 深拷贝示例2 - 序列化
List<Person> deepCopy2 = deepCopy(original);
deepCopy2.get(0).setName("David");
System.out.println(original.get(0).getName()); // 输出 "Bob"
// 深拷贝示例3 - Apache Commons Lang
List<Person> deepCopy3 = SerializationUtils.clone(original);
deepCopy3.get(0).setName("Eve");
System.out.println(original.get(0).getName()); // 输出 "Bob"
}
// 使用序列化实现深拷贝
public static <T> List<T> deepCopy(List<T> src) throws IOException, ClassNotFoundException {
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(byteOut);
out.writeObject(src);
ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
ObjectInputStream in = new ObjectInputStream(byteIn);
@SuppressWarnings("unchecked")
List<T> dest = (List<T>) in.readObject();
return dest;
}
}
选择浅拷贝还是深拷贝取决于你的具体需求。如果集合中的元素是不可变的,或者你希望新旧集合共享元素,使用浅拷贝更高效。如果需要完全独立的副本,则应使用深拷贝。