1. 引言

在 Java 开发中,我们经常需要在不同的代码模块之间共享数据。共享数据的方式可以是直接共享内存地址,也可以是创建副本进行独立操作。本文将围绕浅拷贝(Shallow Copy)深拷贝(Deep Copy)展开讨论,帮助你理解它们的原理、区别以及使用场景。

2. 引用 vs 值

在 Java 中,大多数变量存储的是对象的引用(reference)而非实际值本身。例如:

User user1 = new User("Alice");
User user2 = user1;

此时 user1user2 指向的是同一块内存地址,任何一方对对象的修改都会反映在另一方上。

Screenshot-2022-03-21-at-07.36.22

这种机制的好处是节省内存,因为传递的是引用而非整个对象。但这也意味着多个变量可能共享同一份数据,一旦其中一个修改了对象内容,其他变量也会受到影响

⚠️ 注意:这种行为仅适用于对象类型(Object),基本类型(如 int、long)是直接存储值的,不存在引用共享的问题。

3. 什么是浅拷贝(Shallow Copy)

当我们希望两个变量拥有各自的对象副本,以避免相互影响时,可以使用浅拷贝。

浅拷贝是指:创建一个新对象,并复制原对象的所有字段。对于基本类型字段,复制的是实际值;对于引用类型字段,复制的是引用地址。

示例代码如下:

class User {
    private String name;
    private List<String> hobbies;

    // 构造函数、getter、setter 省略
}

User user1 = new User("Alice", Arrays.asList("reading", "coding"));
User user2 = new User(user1); // 假设构造函数实现为浅拷贝

此时,user1user2 是两个不同的对象,但如果 hobbies 是引用类型,则它们指向的是同一个列表:

Screenshot-2022-03-21-at-08.40.05

✅ 优点:实现简单,性能较好
❌ 缺点:嵌套引用对象仍被共享,存在数据污染风险

4. 什么是深拷贝(Deep Copy)

深拷贝是对浅拷贝的一种改进:不仅复制对象本身,还递归复制其所有引用的对象,确保两个对象之间完全独立。

例如:

User user1 = new User("Alice", Arrays.asList("reading", "coding"));
User user2 = deepCopy(user1); // 深拷贝实现

此时,user1user2hobbies 是两个独立的列表,互不影响:

Screenshot-2022-03-21-at-08.39.28

✅ 优点:对象之间完全隔离,避免数据污染
❌ 缺点:实现复杂,性能开销大,尤其在嵌套结构复杂时

5. 不可变性 vs 拷贝

拷贝的目的是让多个对象拥有独立的数据副本。但如果你的对象是不可变的(immutable),那么你就不需要拷贝了。

例如:

class User {
    private final String name;
    private final List<String> hobbies;

    public User(String name, List<String> hobbies) {
        this.name = name;
        this.hobbies = Collections.unmodifiableList(new ArrayList<>(hobbies));
    }

    public String getName() { return name; }
    public List<String> getHobbies() { return hobbies; }
}

此时,无论多少个对象引用这个 User,都无法修改其内部状态,因此无需拷贝。

⚠️ 踩坑提醒:不要以为字段是 final 就是不可变的,如果字段本身是可变对象(如 ListMap),那它仍然是可以被修改的。

例如:

User user1 = new User("Alice", new ArrayList<>(Arrays.asList("reading", "coding")));
user1.getHobbies().add("swimming"); // ❌ 仍可修改

6. 写时复制(Copy-on-Write)

有时候我们希望对象是可变的,但又不想一开始就进行深拷贝。这时可以使用 Copy-on-Write 模式。

原理是:多个对象共享同一份数据,只有在需要修改时才进行拷贝,从而节省内存和性能开销。

示例代码如下:

class Original {
    private String value;

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}

class CopyOnWrite {
    private Original original;
    private boolean copied = false;

    public CopyOnWrite(Original original) {
        this.original = original;
    }

    public String getValue() {
        return original.getValue();
    }

    public void setValue(String newValue) {
        if (!copied) {
            this.original = deepCopy(original); // 真正修改前才深拷贝
            copied = true;
        }
        original.setValue(newValue);
    }
}

✅ 优点:兼顾性能与数据隔离
❌ 缺点:实现复杂,需谨慎处理线程安全

7. 总结

特性 浅拷贝 深拷贝 不可变对象 Copy-on-Write
是否复制引用 N/A N/A
是否完全独立 ✅(写时独立)
是否适合嵌套结构
性能开销 中等
是否线程安全 ✅(写时复制)

📌 建议

  • 如果对象结构简单,且无需嵌套修改,使用浅拷贝即可。
  • 如果对象结构复杂,或者需要独立修改,必须使用深拷贝。
  • 如果对象不希望被修改,优先考虑使用不可变设计。
  • 如果对象可能被多个线程共享,但修改较少,考虑使用 Copy-on-Write 模式。

最终选择哪种方式,取决于你的业务场景和性能需求。


原始标题:Differences Between a Deep Copy and a Shallow Copy