JAVA浅克隆和深克隆

文章目录

  • 前言
  • 一、浅克隆
    • [1. 实体对象](#1. 实体对象)
    • [2. 单元测试](#2. 单元测试)
    • [3. 输出](#3. 输出)
  • 二、深克隆
    • [1. Cloneable](#1. Cloneable)
      • [1.1 实体对象](#1.1 实体对象)
      • [1.2 单元测试](#1.2 单元测试)
      • [1.3 输出](#1.3 输出)
    • [2. Serializable](#2. Serializable)
      • [2.1 实体对象](#2.1 实体对象)
      • [2.2 单元测试](#2.2 单元测试)
      • [2.3 输出](#2.3 输出)
  • 总结

前言

克隆的使用场景主要为需要将对象将源对象复制一份出来,保证后续改动不会对源对象造成影响。

浅克隆复制基本类型变量,改动克隆对象引用对象属性,会对源对象造成影响。

深克隆复制基本类型变量和引用类型变量,和源对象完全分割,改动克隆对象不会影响源对象。


一、浅克隆

1. 实体对象

java 复制代码
package com.student.model;

/**
 * Create by zjg on 2024/7/30
 */
public class Student {
    private int id;
    private String name;
    private int age;
    private String gender;
    private Address address;
    public Student() {
    }
    public Student(int id, String name, int age, String gender, Address address) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.address = address;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                ", address=" + address +
                '}';
    }

    public static class Address implements Cloneable{
        private String province;
        private String city;
        private String area;
        public Address(String province, String city, String area) {
            this.province = province;
            this.city = city;
            this.area = area;
        }

        public String getProvince() {
            return province;
        }

        public void setProvince(String province) {
            this.province = province;
        }

        public String getCity() {
            return city;
        }

        public void setCity(String city) {
            this.city = city;
        }

        public String getArea() {
            return area;
        }

        public void setArea(String area) {
            this.area = area;
        }

        @Override
        public String toString() {
            return "Address{" +
                    "province='" + province + '\'' +
                    ", city='" + city + '\'' +
                    ", area='" + area + '\'' +
                    '}';
        }
    }
}

2. 单元测试

java 复制代码
package test.z202401;

import com.student.model.Student;
import org.springframework.beans.BeanUtils;

/**
 * Create by zjg on 2024/7/30
 */
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student student=new Student(1,"张三",18,"男",new Student.Address("北京","北京","朝阳区"));
        Student clone = new Student();
        BeanUtils.copyProperties(student,clone);
        System.out.println("修改前------");
        System.out.println(student);
        System.out.println(clone);
        clone.setId(2);//修改克隆对象的id
        clone.setName("李四");//修改克隆对象的名字
        Student.Address address = clone.getAddress();
        address.setProvince("山东省");//修改克隆对象的省
        address.setCity("济南市");//修改克隆对象的市
        address.setArea("市中区");//修改克隆对象的区
        clone.setAddress(address);
        System.out.println("修改后------");
        System.out.println(student);
        System.out.println(clone);
    }
}

3. 输出

bash 复制代码
修改前------
Student{id=1, name='张三', age=18, gender='男', address=Address{province='北京', city='北京', area='朝阳区'}}
Student{id=1, name='张三', age=18, gender='男', address=Address{province='北京', city='北京', area='朝阳区'}}
修改后------
Student{id=1, name='张三', age=18, gender='男', address=Address{province='山东省', city='济南市', area='市中区'}}
Student{id=2, name='李四', age=18, gender='男', address=Address{province='山东省', city='济南市', area='市中区'}}

我们修改了克隆对象的id,name和address对象,对象1的id和name没有发生变化,但是对于我们自定义的Address对象修改却影响了对象1的数据,可见它们使用的是同一个Address对象。

二、深克隆

深度克隆有Cloneable和Serializable两种实现方式,都能解决上述问题,接下来我们逐个介绍

1. Cloneable

1.1 实体对象

java 复制代码
package com.student.model;

/**
 * Create by zjg on 2024/7/30
 */
public class Student implements Cloneable{
    private int id;
    private String name;
    private int age;
    private String gender;
    private Address address;
    public Student() {
    }
    public Student(int id, String name, int age, String gender, Address address) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.address = address;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }
    public Object clone() throws CloneNotSupportedException {
        Student student = (Student)super.clone();
        student.address = (Address)this.address.clone();
        return student;
    }
    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                ", address=" + address +
                '}';
    }

    public static class Address implements Cloneable{
        private String province;
        private String city;
        private String area;
        public Address(String province, String city, String area) {
            this.province = province;
            this.city = city;
            this.area = area;
        }

        public String getProvince() {
            return province;
        }

        public void setProvince(String province) {
            this.province = province;
        }

        public String getCity() {
            return city;
        }

        public void setCity(String city) {
            this.city = city;
        }

        public String getArea() {
            return area;
        }

        public void setArea(String area) {
            this.area = area;
        }
        public Object clone() throws CloneNotSupportedException {
            Address address = (Address)super.clone();
            return address;
        }
        @Override
        public String toString() {
            return "Address{" +
                    "province='" + province + '\'' +
                    ", city='" + city + '\'' +
                    ", area='" + area + '\'' +
                    '}';
        }
    }
}

1.2 单元测试

java 复制代码
package test.z202401;

import com.student.model.Student;

/**
 * Create by zjg on 2024/7/30
 */
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student student=new Student(1,"张三",18,"男",new Student.Address("北京","北京","朝阳区"));
        Student clone = (Student)student.clone();
        System.out.println("修改前------");
        System.out.println(student);
        System.out.println(clone);
        clone.setId(2);//修改克隆对象的id
        clone.setName("李四");//修改克隆对象的名字
        Student.Address address = clone.getAddress();
        address.setProvince("山东省");//修改克隆对象的省
        address.setCity("济南市");//修改克隆对象的市
        address.setArea("市中区");//修改克隆对象的区
        clone.setAddress(address);
        System.out.println("修改后------");
        System.out.println(student);
        System.out.println(clone);
    }
}

1.3 输出

bash 复制代码
修改前------
Student{id=1, name='张三', age=18, gender='男', address=Address{province='北京', city='北京', area='朝阳区'}}
Student{id=1, name='张三', age=18, gender='男', address=Address{province='北京', city='北京', area='朝阳区'}}
修改后------
Student{id=1, name='张三', age=18, gender='男', address=Address{province='北京', city='北京', area='朝阳区'}}
Student{id=2, name='李四', age=18, gender='男', address=Address{province='山东省', city='济南市', area='市中区'}}

可以看出修改克隆对象的属性,不会对原对象造成影响

2. Serializable

2.1 实体对象

java 复制代码
package com.student.model;

import java.io.Serializable;

/**
 * Create by zjg on 2024/7/30
 */
public class Student implements Serializable {
    private int id;
    private String name;
    private int age;
    private String gender;
    private Address address;
    public Student() {
    }
    public Student(int id, String name, int age, String gender, Address address) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.address = address;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                ", address=" + address +
                '}';
    }

    public static class Address implements Serializable {
        private String province;
        private String city;
        private String area;
        public Address(String province, String city, String area) {
            this.province = province;
            this.city = city;
            this.area = area;
        }

        public String getProvince() {
            return province;
        }

        public void setProvince(String province) {
            this.province = province;
        }

        public String getCity() {
            return city;
        }

        public void setCity(String city) {
            this.city = city;
        }

        public String getArea() {
            return area;
        }

        public void setArea(String area) {
            this.area = area;
        }

        @Override
        public String toString() {
            return "Address{" +
                    "province='" + province + '\'' +
                    ", city='" + city + '\'' +
                    ", area='" + area + '\'' +
                    '}';
        }
    }
}

2.2 单元测试

java 复制代码
package test.z202401;

import com.student.model.Student;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
 * Create by zjg on 2024/7/30
 */
public class Test {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Student student=new Student(1,"张三",18,"男",new Student.Address("北京","北京","朝阳区"));
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(student);

        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bais);
        Student clone = (Student)ois.readObject();
        System.out.println("修改前------");
        System.out.println(student);
        System.out.println(clone);
        clone.setId(2);//修改克隆对象的id
        clone.setName("李四");//修改克隆对象的名字
        Student.Address address = clone.getAddress();
        address.setProvince("山东省");//修改克隆对象的省
        address.setCity("济南市");//修改克隆对象的市
        address.setArea("市中区");//修改克隆对象的区
        clone.setAddress(address);
        System.out.println("修改后------");
        System.out.println(student);
        System.out.println(clone);
    }
}

2.3 输出

bash 复制代码
修改前------
Student{id=1, name='张三', age=18, gender='男', address=Address{province='北京', city='北京', area='朝阳区'}}
Student{id=1, name='张三', age=18, gender='男', address=Address{province='北京', city='北京', area='朝阳区'}}
修改后------
Student{id=1, name='张三', age=18, gender='男', address=Address{province='北京', city='北京', area='朝阳区'}}
Student{id=2, name='李四', age=18, gender='男', address=Address{province='山东省', city='济南市', area='市中区'}}

实现序列化接口,通过对象流产生的对象也是不会对原对象产生影响。


总结

回到顶部

深度克隆的两种使用方式略有区别,大家可以根据自己的使用习惯来

实践是检验真理的唯一标准。

相关推荐
nagualky1234 小时前
GPT-4 系列退役在即:一套可回滚的模型迁移验收法
java·开发语言·ai·架构
今天的砖头有点烫手啊4 小时前
Java 8 Stream 原理拆解:惰性求值与并行流陷阱
java·jvm
starzy19904 小时前
Flink 任务调度 Graph 源码深度剖析:从 StreamGraph 到 ExecutionGraph 的三层演进
java·大数据·flink
Eyfcom5 小时前
〖实战〗快运系统 Oracle 性能优化:从“能用”到“扛住双11”的 Java + Spring Boot 实战
java·oracle·性能优化·快递管理系统
m0_587383005 小时前
碰碰好评卡功能落地全流程实战指南 附核心逻辑与常见问题解决方案
java·前端·数据库·后端·struts·需求分析
cheems95275 小时前
从统一响应到 Swagger:一篇讲清微服务接口文档设计未命名
java·微服务·架构·状态模式
Y3815326625 小时前
SerpBase + RAG 实战:用搜索 API 给知识库接上实时数据,回答不再过期
java·服务器·数据库
开开心心就好5 小时前
文件关联被破坏怎么修?免费工具一键修复
java·服务器·开发语言·pdf·ocr·启发式算法·宽度优先
不停喝水5 小时前
【前端转全栈java速通课】 项目实战④12-14节 拦截器过滤器和全局配置-cors跨域设置-token体系-利用session做验证码
java·开发语言·前端·ai·容器
鱼宵5 小时前
Spring AI RAG 问答助手:回答带引用,AI 不再睁眼说瞎话
java·人工智能·spring·springai