Java中深拷贝和浅拷贝详解学习

一、什么是深拷贝?什么是浅拷贝?

Java中深拷贝和浅拷贝都是与Java中对象的复制有关。Java 中的深拷贝和浅拷贝通常通过实现 Cloneable 接口并重写 clone() 方法来实现。

浅拷贝:

在浅拷贝中,只有对象的基本数据类型属性被复制,而对象的引用类型属性则只是被复制了引用。这意味着新对象和原对象共享引用类型对象。

深拷贝:

在深拷贝中,会递归地复制对象及其所有子对象(无论是基本数据类型还是引用对象),确保新对象与原始对象完全独立。

二、浅拷贝示例

java 复制代码
@Data
public class Teacher implements Cloneable{
    private String name;
    private int age;
    private School school;

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

    public Teacher(String name, int age, School school) {
        this.name = name;
        this.age = age;
        this.school = school;
    }
}

@Data
@Accessors(chain = true)
public class Teacher implements Cloneable{
    private String name;
    private int age;
    private School school;

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

    public Teacher(String name, int age, School school) {
        this.name = name;
        this.age = age;
        this.school = school;
    }
}

@Slf4j
public class Main {
    public static void main(String[] args) throws CloneNotSupportedException {
        School school = new School("AAA School");
        Teacher teacher = new Teacher("Alice", 20, school);
        Teacher backTeacher = (Teacher) teacher.clone();

        backTeacher.setName("Tom");
        backTeacher.setAge(18);
        backTeacher.getSchool().setName("BBB School");

        //将对象序列化为json字符串进行日志打印
        String jsonTeacher = JSON.toJSONString(teacher);
        String jsonBackTeacher = backTeacher.toString();

        log.info("[Teacher] jsonTeacher name is : {}", jsonTeacher);
        log.info("[Teacher] jsonBackTeacher name is : {}", jsonBackTeacher);
    }
}

输出结果:

java 复制代码
15:46:02.300 [main] INFO com.example.demo.entity.Main - [Teacher] teacher name is : {"age":20,"name":"Alice","school":{"name":"BBB School"}}
15:46:02.303 [main] INFO com.example.demo.entity.Main - [Teacher] teacher name is : Teacher(name=Tom, age=18, school=School(name=BBB School))

可以看到浅拷贝后,基本的数据类型修改没有影响,而对于引用对象数据修改后,原对象和复制的对象会联动修改

三、深拷贝示例

java 复制代码
@Data
@Accessors(chain = true)
public class Teacher implements Cloneable{
    private String name;
    private int age;
    private School school;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Teacher cloneTeacher = (Teacher) super.clone();
        cloneTeacher.school = (School) school.clone(); //深拷贝School对象
        return cloneTeacher;
    }

    public Teacher(String name, int age, School school) {
        this.name = name;
        this.age = age;
        this.school = school;
    }
}

@Data
@Accessors(chain = true)
public class School implements Cloneable{
    private String name;

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

    public School(String name) {
        this.name = name;
    }
}

@Slf4j
public class Main {
    public static void main(String[] args) throws CloneNotSupportedException {
        School school = new School("AAA School");
        Teacher teacher = new Teacher("Alice", 20, school);
        Teacher backTeacher = (Teacher) teacher.clone();

        backTeacher.setName("Tom");
        backTeacher.setAge(18);
        backTeacher.getSchool().setName("BBB School");

        //将对象序列化为json字符串进行日志打印
        String jsonTeacher = JSON.toJSONString(teacher);
        String jsonBackTeacher = backTeacher.toString();

        log.info("[Teacher] jsonTeacher name is : {}", jsonTeacher);
        log.info("[Teacher] jsonBackTeacher name is : {}", jsonBackTeacher);
    }
}

输出结果:

java 复制代码
16:49:45.213 [main] INFO com.example.demo.entity.Main - [Teacher] jsonTeacher name is : {"age":20,"name":"Alice","school":{"name":"AAA School"}}
16:49:45.215 [main] INFO com.example.demo.entity.Main - [Teacher] jsonBackTeacher name is : Teacher(name=Tom, age=18, school=School(name=BBB School))

可以看到深拷贝后,原对象和拷贝后的对象无论是基本数据还是引用对象的数据都相互独立,互不影响。

四、项目中如何实现深拷贝

在项目中会借助fastjson库通过序列化+反序列化的方式实现对于复制对象的深拷贝

代码示例如下:

java 复制代码
@Slf4j
public class Main {
    /**
     * 借助fastjson库 通过序列化 + 反序列化的方式实现对象的深拷贝
     *
     * @param object
     * @param <T>
     * @return
     */
    public static <T> T deepCopy(T object) {
        String jsonString = JSON.toJSONString(object);
        return JSON.parseObject(jsonString, (Class<? extends T>) object.getClass());
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        School school = new School("AAA School");
        Teacher teacher = new Teacher("Alice", 20, school);
        //Teacher backTeacher = (Teacher) teacher.clone();
        Teacher backTeacher = deepCopy(teacher);

        backTeacher.setName("Tom");
        backTeacher.setAge(18);
        backTeacher.getSchool().setName("BBB School");

        //将对象序列化为json字符串进行日志打印
        String jsonTeacher = JSON.toJSONString(teacher);
        String jsonBackTeacher = backTeacher.toString();

        log.info("[Teacher] jsonTeacher name is : {}", jsonTeacher);
        log.info("[Teacher] jsonBackTeacher name is : {}", jsonBackTeacher);
    }
}

输出结果:

java 复制代码
17:27:21.649 [main] INFO com.example.demo.entity.Main - [Teacher] jsonTeacher name is : {"age":20,"name":"Alice","school":{"name":"AAA School"}}
17:27:21.653 [main] INFO com.example.demo.entity.Main - [Teacher] jsonBackTeacher name is : Teacher(name=Tom, age=18, school=School(name=BBB School))
相关推荐
Amarantine、沐风倩✨2 分钟前
设计一个监控摄像头物联网IOT(webRTC、音视频、文件存储)
java·物联网·音视频·webrtc·html5·视频编解码·七牛云存储
Kisorge28 分钟前
【C语言】指针数组、数组指针、函数指针、指针函数、函数指针数组、回调函数
c语言·开发语言
机智的叉烧32 分钟前
前沿重器[57] | sigir24:大模型推荐系统的文本ID对齐学习
人工智能·学习·机器学习
路在脚下@1 小时前
spring boot的配置文件属性注入到类的静态属性
java·spring boot·sql
森屿Serien1 小时前
Spring Boot常用注解
java·spring boot·后端
量子-Alex1 小时前
【多模态聚类】用于无标记视频自监督学习的多模态聚类网络
学习·音视频·聚类
轻口味2 小时前
命名空间与模块化概述
开发语言·前端·javascript
吉大一菜鸡2 小时前
FPGA学习(基于小梅哥Xilinx FPGA)学习笔记
笔记·学习·fpga开发
苹果醋32 小时前
React源码02 - 基础知识 React API 一览
java·运维·spring boot·mysql·nginx
晓纪同学2 小时前
QT-简单视觉框架代码
开发语言·qt