java的深拷贝与浅拷贝

1.核心区别

深拷贝(Deep Copy) 和 浅拷贝(Shallow Copy) 是对象复制的两种核心方式,主要区别在于对 引用类型字段 的处理

特性 浅拷贝 深拷贝
对象复制范围 只复制对象本身(基本类型字段 + 引用地址) 递归复制对象及其引用的所有子对象
引用类型字段 仅复制引用地址(新旧对象共享同一对象) 创建全新独立对象(无共享)
内存关系 原对象和拷贝对象部分共享内存 完全独立的内存空间
修改影响 修改引用字段会影响原对象 修改引用字段 不影响 原对象
默认实现 Object.clone() 默认行为 需手动实现
性能 快(仅复制一层) 慢(递归复制整个对象树)

例如:对象是一本书,浅拷贝就是把目录复制了一份,而深拷贝是吧整本书复制了一份。

2.技术细节解析

java 复制代码
class Address implements Cloneable {
    String city;

    public Address(String city) {
        this.city = city;
    }

    // 浅拷贝
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

class Person implements Cloneable {
    String name;
    Address address;

    public Person(String name, Address address) {
        this.name = name;
        this.address = address;
    }

    // 浅拷贝
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    // 深拷贝
    protected Person deepClone() throws CloneNotSupportedException {
        Person cloned = (Person) super.clone();
        cloned.address = (Address) address.clone(); // 关键:拷贝引用对象
        return cloned;
    }
}

public class CopyDemo {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address addr = new Address("Beijing");
        Person p1 = new Person("Tom", addr);

        // 浅拷贝
        Person p2 = (Person) p1.clone();
        // 深拷贝
        Person p3 = p1.deepClone();

        // 修改原始对象的引用类型字段
        p1.address.city = "Shanghai";

        System.out.println("p2.address.city (浅拷贝): " + p2.address.city); // 输出 Shanghai
        System.out.println("p3.address.city (深拷贝): " + p3.address.city); // 输出 Beijing
    }
}

使用序列化实现深拷贝

java 复制代码
import java.io.*;

public class DeepCopyUtil {
    public static <T extends Serializable> T deepCopy(T object) {
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
             ObjectOutputStream oos = new ObjectOutputStream(bos)) {
            
            oos.writeObject(object); // 序列化
            try (ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
                 ObjectInputStream ois = new ObjectInputStream(bis)) {
                return (T) ois.readObject(); // 反序列化生成新对象
            }
        } catch (Exception e) {
            throw new RuntimeException("Deep copy failed", e);
        }
    }
}

// 使用
Person deepCopy = DeepCopyUtil.deepCopy(original);
deepCopy.address.setCity("Tokyo"); 
System.out.println(original.address.getCity()); // 输出 "Paris"(原对象不受影响)

3.关键使用场景

场景 推荐方式 原因
对象不含引用类型字段 浅拷贝 性能高且安全
引用字段是不可变对象 浅拷贝 String/包装类等不可变对象无需深拷贝
对象包含可变引用字段 深拷贝 避免意外修改原对象
复杂嵌套对象图 序列化深拷贝 避免递归实现的复杂性

4.注意事项

  1. Cloneable 接口的缺陷:

    是标记接口(无方法),但必须实现才能调用 Object.clone()

    clone() 方法是 protected,需重写为 public

  2. 深拷贝陷阱:

    递归实现需确保所有嵌套对象都支持克隆

    循环引用会导致递归无限循环(序列化可解决)

  3. 最佳实践:

    优先使用 不可变对象(如 String、LocalDateTime)

    复杂对象推荐用 序列化法 实现深拷贝

    避免深拷贝:考虑用 防御性拷贝构造器(如 new ArrayList<>(originalList))

💡 终极原则:如果对象需要完全隔离修改,用深拷贝;如果共享数据无风险或用不可变对象,用浅拷贝。

相关推荐
i***13243 分钟前
SpringCloud实战十三:Gateway之 Spring Cloud Gateway 动态路由
java·spring cloud·gateway
计算机徐师兄5 分钟前
Java基于微信小程序的食堂线上预约点餐系统【附源码、文档说明】
java·微信小程序·食堂线上预约点餐系统小程序·食堂线上预约点餐微信小程序·java食堂线上预约点餐小程序·食堂线上预约点餐小程序·食堂线上预约点餐系统微信小程序
无心水1 小时前
【分布式利器:腾讯TSF】10、TSF故障排查与架构评审实战:Java架构师从救火到防火的生产哲学
java·人工智能·分布式·架构·限流·分布式利器·腾讯tsf
Boilermaker19928 小时前
[Java 并发编程] Synchronized 锁升级
java·开发语言
Cherry的跨界思维8 小时前
28、AI测试环境搭建与全栈工具实战:从本地到云平台的完整指南
java·人工智能·vue3·ai测试·ai全栈·测试全栈·ai测试全栈
MM_MS8 小时前
Halcon变量控制类型、数据类型转换、字符串格式化、元组操作
开发语言·人工智能·深度学习·算法·目标检测·计算机视觉·视觉检测
꧁Q༒ོγ꧂9 小时前
LaTeX 语法入门指南
开发语言·latex
njsgcs9 小时前
ue python二次开发启动教程+ 导入fbx到指定文件夹
开发语言·python·unreal engine·ue
alonewolf_999 小时前
JDK17新特性全面解析:从语法革新到模块化革命
java·开发语言·jvm·jdk
一嘴一个橘子9 小时前
spring-aop 的 基础使用(啥是增强类、切点、切面)- 2
java