详解深浅拷贝:从原理到实现的完整指南

目录

深拷贝和浅拷贝的区别?

实现深拷贝的三种方法是什么?

实现Cloneable接口并重写里面的clone()方法:

序列化和反序列化,实现Serializable接口

手动递归克隆


深拷贝和浅拷贝的区别?

浅拷贝在复制非引用字段时 整体复制,复制引用字段时 只复制源对象存储的引用对象的内存存储地址,不会复制一份新的内存内容

深拷贝在复制时不论引用字段还是非引用字段,全体都再复制一份

举例说明:

cs 复制代码
class Person
{
    // 值类型
    public int Age;
    // 引用类型(字符串/数组/类都是)
    public string Name;
}

// 原对象
Person p1 = new Person { Age = 18, Name = "张三" };
// 浅拷贝 → 创建了新对象 p2
Person p2 = (Person)p1.MemberwiseClone(); 

此时p2中复制的是Age = 18;

还有Name这个变量所对应的内存地址,没有再复制一个张三

此时内存里只有一个张三,两个对象的 Name 指向同一块内存
p1 (新对象) Age → 18(复制了新值) Name → 内存地址 A → "张三" p2 (另一个新对象) Age → 18(复制了新值) Name → 内存地址 A → 【和 p1 共用同一份字符串】
如果是深拷贝

则在内存里有两个对象的Name,但是不是指向源对象的Name的地址

也就是有两个内存不同位置的"张三"存在

实现深拷贝的三种方法是什么?

实现Cloneable接口并重写里面的clone()方法:

对象实现Cloneable接口并重写clone()方法,同时对象里面的引用字符类型也要实现Cloneable接口,重写clone()方法

java 复制代码
class MyClass implements Cloneable {
    private String field1;
    private NestedClass nestedObject;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        MyClass cloned = (MyClass) super.clone();//深拷贝一层
        cloned.nestedObject = (NestedClass) nestedObject.clone(); // 深拷贝内部的引用对象
        return cloned;
    }
}

class NestedClass implements Cloneable {
    private int nestedField;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

克隆时应该递归克隆,上述只克隆了一层,遇到引用类型 → 自动调用 clone (),不管深度多少层。

java 复制代码
class A implements Cloneable {
    B b;

    @Override
    public Object clone() {
        A a = (A) super.clone();
        a.b = (B) b.clone(); // 递归:B 也会 clone 它内部的对象
        return a;
    }
}

class B implements Cloneable {
    C c;

    @Override
    public Object clone() {
        B b = (B) super.clone();
        b.c = (C) c.clone(); // 继续递归
        return b;
    }
}

class C implements Cloneable {
    // ...
}

序列化和反序列化,实现Serializable接口

首先实现Serializable接口(表明可以序列化),然后把整个对象序列化,写入流,然后读出来生成新的对象

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

class MyClass implements Serializable {
    private String field1;
    private NestedClass nestedObject;

    public MyClass deepCopy() {
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();//创建字节数组存放数据
            ObjectOutputStream oos = new ObjectOutputStream(bos);//创建对象输出流
            oos.writeObject(this);
            oos.flush();
            oos.close();

            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());//从内存字节数组读取
            ObjectInputStream ois = new ObjectInputStream(bis);//创建输入流
            return (MyClass) ois.readObject();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
            return null;
        }
    }
}

class NestedClass implements Serializable {
    private int nestedField;
}

注意:try前半段的流程是,先创建好两个流,执行到第三行时,先写入当前对象,然后由ObjectOutputStream()把对象转化成字节(序列化),再传给ByteArrayOutputStream(),存入字节数组

手动递归克隆

与第一种方法类似,都是有多少个引用类型的字符串就写多少个递归函数,但不用实现接口和重写方法,适用于复杂度不高的情况

java 复制代码
class MyClass {
    private String field1;
    private NestedClass nestedObject;

    public MyClass deepCopy() {
        MyClass copy = new MyClass();
        copy.setField1(this.field1);
        copy.setNestedObject(this.nestedObject.deepCopy());
        return copy;
    }
}

class NestedClass {
    private int nestedField;

    public NestedClass deepCopy() {
        NestedClass copy = new NestedClass();
        copy.setNestedField(this.nestedField);
        return copy;
    }
}

方法一三实现操作都类似,但方法三不用重写方法与实现接口,再复杂度不高的时候选方法三,较高的时候选方法二

相关推荐
学长毕设2 小时前
基于SpringBoot的实验室资产管理系统
java·spring boot·后端
zzu123zsw3 小时前
从臃肿的模板调用到声明式契约:深入 UniHttp 动态代理与多渠道生命周期扩展
java·spring boot·microsoft·unihttp
源码集结号4 小时前
云诊所门诊系统源码,基于SpringBoot+Vue.js架构,支持多租户设计与Docker容器化部署
java·spring boot·源码·医院信息系统·门诊系统·诊所系统
努力的小雨4 小时前
给 AI 眼镜开发应用有多难?我从零做了一个陪练,还上架了
后端
论文复现现场4 小时前
WRF、FEA 能用 L40S 加速吗?求解器检查、断点恢复与长期运行
java·数据库·算法·wrf·有限元分析·gpu计算·断点续算
啃瓜子的松鼠5 小时前
泛微OAe9-后端二开异步调用
java
秋天的怀念_David6 小时前
第二十一夜 · 数字黑洞与西西弗斯的惩罚
java·程序人生·算法
excel6 小时前
双 Token 与前端使用 Crypto 公私钥鉴权换 Token,哪种方案更好?
前端·后端
外收内放6 小时前
Python基础语法练习题(73)
java·前端·python
Wang's Blog6 小时前
Java 项目实战: 交友项目 - 环信后台发送消息测试
java·交友