← 返回题目列表

原型模式中的浅拷贝和深拷贝有什么区别?

高频 中等 第 9 / 25 题 更新于 2026/07/28
原型模式浅拷贝深拷贝可变对象Java

简化版

浅拷贝只复制对象本身,引用类型字段仍然指向同一个对象;深拷贝不仅复制对象本身,也复制内部可变引用对象。原型模式中如果对象包含可变字段,必须认真判断是否需要深拷贝,否则副本和原型会互相影响。

详细版

区别可以这样看:

类型对象本身引用字段指向
浅拷贝创建新对象仍共享原来的引用对象
深拷贝创建新对象引用字段也创建新对象

例子:

class User {
    String name;
    List<String> roles;
}

浅拷贝后:

user1 != user2
user1.roles == user2.roles

深拷贝后:

user1 != user2
user1.roles != user2.roles

如果 roles 会被修改,应该深拷贝;如果引用对象是不可变的,可以安全共享。

完整版教学

一、浅拷贝复制到哪一层

浅拷贝只复制第一层对象。

class Profile implements Cloneable {
    String name;
    List<String> tags;

    protected Profile clone() throws CloneNotSupportedException {
        return (Profile) super.clone();
    }
}

super.clone() 会创建新的 Profile 对象,但 tags 仍然指向原来的列表。

结果是:

Profile p1 = new Profile();
Profile p2 = p1.clone();

p1 != p2;          // true
p1.tags == p2.tags; // true

这就是浅拷贝。

二、浅拷贝的风险

如果副本修改列表:

p2.tags.add("new");

原型对象的 tags 也会变化,因为它们共享同一个列表。

这会导致非常隐蔽的 bug:看起来复制出了两个对象,实际内部状态仍然连在一起。

三、深拷贝复制可变引用

深拷贝要为可变引用重新创建对象:

class Profile {
    String name;
    List<String> tags;

    Profile copy() {
        Profile copy = new Profile();
        copy.name = this.name;
        copy.tags = new ArrayList<>(this.tags);
        return copy;
    }
}

此时:

p1 != p2
p1.tags != p2.tags

副本修改 tags 不会影响原型。

四、深拷贝不是所有字段都复制得越深越好

深拷贝会带来成本。

如果对象图很大,完全深拷贝可能很慢,也会占用更多内存。

而有些对象本来就可以共享:

  • String
  • Integer 等包装类型;
  • LocalDateTime 等不可变值对象;
  • 只读配置对象;
  • 枚举。

这些对象通常没必要重新复制。

五、判断深浅拷贝的标准

可以用一个问题判断:

副本修改这个字段时,是否允许影响原型或其他副本?

如果不允许,就要深拷贝或使用不可变对象。

如果允许共享,浅拷贝即可。

例如:

  • 用户权限列表会被修改:深拷贝;
  • 全局只读字典配置:可以共享;
  • 图片二进制大对象只读:可以共享;
  • 临时状态列表:通常深拷贝。

六、常见误区与追问

深浅拷贝应通过引用图而不是术语判断。源对象 A 引用列表 L,浅拷贝得到 B 后满足 A != BA.list == B.list;深拷贝则通常要求 A.list != B.list。若 L 内含2个可变元素,还要继续判断元素引用是否独立,不能只检查集合外壳。

检查维度判定依据
浅拷贝顶层新对象,嵌套引用可能共享
深拷贝约定范围内的可变子图独立

易错点:判断标准是“修改副本会不会影响原对象”,不是复制了几层。

  • 误区:浅拷贝就是两个变量指向同一对象。 那只是引用赋值;浅拷贝至少会创建新的顶层对象。
  • 追问:字符串字段需要深拷贝吗? Java String 不可变,安全共享即可。
  • 误区:深拷贝要求所有引用地址都不同。 不可变对象和有意共享的全局值可以保持同一引用。
  • 追问:数组 clone 属于哪种拷贝? 基本类型数组复制值;对象数组只复制元素引用,因此对元素而言是浅拷贝。
  • 追问:如何写最小测试? 修改副本的嵌套可变字段,断言原对象对应字段未变化。

七、加强记忆

浅拷贝复制对象外壳,引用字段仍共享;深拷贝连内部可变对象也复制。原型模式最重要的判断是可变引用是否能共享,能共享就浅拷贝,不能共享就深拷贝或改成不可变对象。