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,nameaddress对象,对象1的idname没有发生变化,但是对于我们自定义的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='市中区'}}

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


总结

回到顶部

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

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

相关推荐
Lojarro1 分钟前
【Spring】Spring框架之-AOP
java·mysql·spring
莫名其妙小饼干4 分钟前
网上球鞋竞拍系统|Java|SSM|VUE| 前后端分离
java·开发语言·maven·mssql
isolusion16 分钟前
Springboot的创建方式
java·spring boot·后端
zjw_rp44 分钟前
Spring-AOP
java·后端·spring·spring-aop
Oneforlove_twoforjob1 小时前
【Java基础面试题033】Java泛型的作用是什么?
java·开发语言
TodoCoder1 小时前
【编程思想】CopyOnWrite是如何解决高并发场景中的读写瓶颈?
java·后端·面试
向宇it1 小时前
【从零开始入门unity游戏开发之——C#篇24】C#面向对象继承——万物之父(object)、装箱和拆箱、sealed 密封类
java·开发语言·unity·c#·游戏引擎
小蜗牛慢慢爬行1 小时前
Hibernate、JPA、Spring DATA JPA、Hibernate 代理和架构
java·架构·hibernate
星河梦瑾2 小时前
SpringBoot相关漏洞学习资料
java·经验分享·spring boot·安全
黄名富2 小时前
Redis 附加功能(二)— 自动过期、流水线与事务及Lua脚本
java·数据库·redis·lua