聊一聊:深拷贝与浅拷贝,有哪些应用场景

105 阅读3分钟

你好,我是风一样的树懒,一个工作十多年的后端专家,曾就职京东、阿里等多家互联网头部企业。公众号“吴计可师”,已经更新了近百篇高质量的面试相关文章,喜欢的朋友欢迎关注点赞

深克隆与浅克隆的理解及应用实例

一、概念解析

  1. 浅克隆(Shallow Clone)

    • 定义:复制对象的基本类型字段值,对引用类型字段仅复制其内存地址,新旧对象共享同一引用对象。
    • 特点:速度快,但引用类型字段的修改会互相影响。
  2. 深克隆(Deep Clone)

    • 定义:递归复制对象及其所有引用对象,生成完全独立的副本。
    • 特点:数据隔离性好,但实现复杂且性能开销较大。

二、实现方式对比

克隆类型实现方法适用场景
浅克隆默认clone()方法(需实现Cloneable接口)引用对象无需独立修改
深克隆递归调用clone()或序列化/反序列化需完全隔离引用对象的复杂结构

三、代码示例

  1. 浅克隆实现

    class Address implements Cloneable {
        private String city;
        
        public Address(String city) { this.city = city; }
        
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }
    
    class Person implements Cloneable {
        private String name;
        private Address address;
        
        public Person(String name, Address address) {
            this.name = name;
            this.address = address;
        }
        
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone(); // 仅复制address引用
        }
    }
    
    // 使用示例
    Address addr = new Address("北京");
    Person p1 = new Person("张三", addr);
    Person p2 = (Person) p1.clone();
    p2.getAddress().setCity("上海"); // p1的address也会变为"上海"
    
  2. 深克隆实现(递归clone)

    class Person implements Cloneable {
        // ... 同上 ...
        
        @Override
        protected Object clone() throws CloneNotSupportedException {
            Person cloned = (Person) super.clone();
            cloned.address = (Address) address.clone(); // 复制address对象
            return cloned;
        }
    }
    
    // 使用示例
    Person p2 = (Person) p1.clone();
    p2.getAddress().setCity("上海"); // p1的address仍为"北京"
    
  3. 深克隆实现(序列化)

    import java.io.*;
    
    public class DeepCloneUtil {
        public static <T extends Serializable> T deepClone(T obj) {
            try {
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                ObjectOutputStream oos = new ObjectOutputStream(bos);
                oos.writeObject(obj);
                ObjectInputStream ois = new ObjectInputStream(
                    new ByteArrayInputStream(bos.toByteArray()));
                return (T) ois.readObject();
            } catch (Exception e) {
                throw new RuntimeException("深克隆失败", e);
            }
        }
    }
    
    // 使用示例
    Person p2 = DeepCloneUtil.deepClone(p1);
    p2.getAddress().setCity("上海"); // p1不受影响
    

四、应用场景实例

  1. 游戏存档与恢复(深克隆)

    • 需求:玩家存档需完全独立,恢复时不影响当前游戏状态。
    • 实现:深克隆游戏角色对象,确保属性、装备等引用数据独立存储。
  2. 多线程共享配置(浅克隆)

    • 需求:多个线程读取同一配置模板,且模板本身不变。
    • 实现:浅克隆配置对象,共享不变的引用数据,节省内存。
  3. 订单快照生成(深克隆)

    • 需求:订单支付前生成独立快照,避免后续修改影响快照数据。
    • 实现:深克隆订单对象,确保商品、价格等信息完全独立。

五、注意事项

  • 性能考量:深克隆递归复制或序列化可能影响性能,尤其在对象层级深时。
  • 循环引用处理:深克隆需避免对象间循环引用导致的栈溢出,可通过缓存已克隆对象解决。
  • 序列化限制:使用序列化方式时,所有涉及类必须实现Serializable接口,且transient字段不会被复制。

六、总结

  • 浅克隆适用于引用对象无需修改或共享资源场景,实现简单高效。
  • 深克隆确保数据完全隔离,适合需独立副本的复杂结构,但需注意实现复杂度与性能开销。
  • 根据业务需求合理选择克隆策略,必要时结合设计模式(如原型模式)优化对象复制流程。

今天文章就分享到这儿,喜欢的朋友可以关注我的公众号,回复“进群”,可进免费技术交流群。博主不定时回复大家的问题。 公众号:吴计可师