Java中集合的深拷贝与浅拷贝实现

发布于:2025-06-24 ⋅ 阅读:(14) ⋅ 点赞:(0)

Java中集合的深拷贝与浅拷贝实现

在Java中,集合的拷贝分为浅拷贝(shallow copy)和深拷贝(deep copy),理解它们的区别及实现方式非常重要。

浅拷贝(Shallow Copy)

浅拷贝只复制集合本身,而不复制集合中的元素。新集合和原集合共享相同的元素引用。

实现方式

  1. 使用构造函数

    List<String> original = new ArrayList<>();
    original.add("A");
    original.add("B");
    
    List<String> shallowCopy = new ArrayList<>(original);
    
  2. 使用addAll方法

    List<String> shallowCopy = new ArrayList<>();
    shallowCopy.addAll(original);
    
  3. 使用clone方法

    List<String> shallowCopy = (List<String>) original.clone();
    
  4. Java 8+ Stream API

    List<String> shallowCopy = original.stream().collect(Collectors.toList());
    

深拷贝(Deep Copy)

深拷贝不仅复制集合本身,还会递归复制集合中的所有元素。新集合和原集合拥有完全独立的对象。

实现方式

  1. 手动复制元素

    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有拷贝构造函数
    }
    
  2. 使用序列化(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;
    }
    
  3. 使用第三方库

    • 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());
      
  4. Java 8+ Stream API实现深拷贝

    List<Person> deepCopy = original.stream()
        .map(p -> new Person(p.getName())) // 假设Person有拷贝构造函数
        .collect(Collectors.toList());
    

注意事项

  1. 深拷贝要求集合中的元素必须实现Serializable接口(如果使用序列化方式)
  2. 对于复杂对象图,深拷贝可能更复杂,需要考虑循环引用等问题
  3. 深拷贝通常比浅拷贝更消耗资源
  4. 对于不可变对象(如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;
    }
}

选择浅拷贝还是深拷贝取决于你的具体需求。如果集合中的元素是不可变的,或者你希望新旧集合共享元素,使用浅拷贝更高效。如果需要完全独立的副本,则应使用深拷贝。


网站公告

今日签到

点亮在社区的每一天
去签到