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))
相关推荐
颜淡慕潇几秒前
Redis 实现分布式锁:深入剖析与最佳实践(含Java实现)
java·redis·分布式
哆啦A梦的口袋呀2 分钟前
基于Python学习《Head First设计模式》第七章 适配器和外观模式
python·学习·设计模式
恰薯条的屑海鸥5 分钟前
零基础在实践中学习网络安全-皮卡丘靶场(第十期-Over Permission 模块)
学习·安全·web安全·渗透测试·网络安全学习
程序员秘密基地7 分钟前
基于vscode,idea,java,html,css,vue,echart,maven,springboot,mysql数据库,在线考试系统
java·vue.js·spring boot·spring·web app
何中应8 分钟前
【设计模式-5】设计模式的总结
java·后端·设计模式
草莓熊Lotso9 分钟前
【数据结构初阶】--算法复杂度的深度解析
c语言·开发语言·数据结构·经验分享·笔记·其他·算法
海的诗篇_25 分钟前
前端开发面试题总结-JavaScript篇(二)
开发语言·前端·javascript·typescript
吾日三省吾码26 分钟前
Spring 团队详解:AOT 缓存实践、JSpecify 空指针安全与支持策略升级
java·spring·缓存
东京老树根41 分钟前
SAP学习笔记 - 开发27 - 前端Fiori开发 Routing and Navigation(路由和导航)
笔记·学习
风象南44 分钟前
SpringBoot的5种日志输出规范策略
java·spring boot·后端