Java中使用clone实现深克隆方法及原理解析

Java中使用clone实现深克隆

  • 首先,需要了解clone方法实际上实现的是浅克隆,即会创建一个新的对象,如果对象中的属性是基本数据类型则拷贝值,如果是引用数据类型则拷贝内存地址,也就意味着任何一个对象改变都会对其他产生影响。
  • 通过今天的学习,了解到Java中可以通过clone实现深克隆,即克隆出来的对象不会受到其他对象值的影响,它可以看作是一个崭新的对象。
  • 虽然方法比较容易记住,但是不了解其中的原理,查询了很多博客总结了一部分。

1. 实现方法

先将实现方法列出,再进行讲解

  • Person类:属性中存在另一个其他引用类型,需要重写clone方法

    public class Person implements Cloneable {
    
        private Integer age;
        private Student student;
    
        public Person() {
        }
    
        public Person(Integer age, Student student) {
            this.age = age;
            this.student = student;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
    
        public Student getStudent() {
            return student;
        }
    
        public void setStudent(Student student) {
            this.student = student;
        }
    
        @Override
        public String toString() {
            return "Person{" +
                    "age=" + age +
                    ", student=" + student +
                    '}';
        }
    
        @Override
        public Object clone() throws CloneNotSupportedException {
            Person person = (Person) super.clone();
            person.student = (Student) student.clone();
            return person;
        }
    }
    
    
  • Student类:需要重写clone

    public class Student implements Cloneable{
    
        private int id;
    
        public Student() {
        }
    
        public Student(int id) {
            this.id = id;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
    
        @Override
        public String toString() {
            return "Student{" +
                    "id=" + id +
                    '}';
        }
    
        @Override
        public Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }
    
    
  • Test类:测试

    public class Test {
        public static void main(String[] args) throws CloneNotSupportedException {
            Student s1 = new Student(1001);
            Person p1 = new Person(20,s1);
    
            Person p2 = (Person) p1.clone();
            p2.setAge(30);
    
            System.out.println(p1);//Person{age=20, student=Student{id=1001}}
            System.out.println(p2);//Person{age=30, student=Student{id=1001}}
        }
    }
    

    显然对p2的属性进行修改,没有影响到p1,说明深克隆成功


2. 实现原理

2.1 基本数据类型和String

  • 首先,对于基本数据类型,对于他们的拷贝没有太多疑问,直接将值拷贝过来,不会相互影响,对于一个引用只存在基本数据类型的情况下,我们也可以认为它是一种“深克隆”

  • 对于String类型,它是一种引用类型,但是它的特殊性在于,它是一个不可改变的类,String类中的函数不能更改自身的值,所以表面上String类型和基本类型一样,好像是实现了“深克隆”,其实String类的地址还是相同的,指向的都是一个地址,只是由于无法改变值的特性,给我们一种“深克隆”的假象。

  • 对于只包含基本数据类型和String的引用类型来说

在这里插入图片描述

可以看的出来,String其实指向的是同一个地址,只是由于String类自身的特殊性,我们不要再重写它的clone方法


2.2 除String外的其他引用类型

和String类型不同,其他引用类型是可变的,所以我们再用clone进行拷贝时,就会造成对象值之间的相互影响

拿1中的程序举例,如果我们Student中不进行clone方法的重写,Person类中也不对Student类进行特殊处理,那么图解应该是这样的

:Person类和Student类,我没有String类型的属性,是不想让大家看图误解,实际也可以把它看作是“深克隆”(不严谨),即和基本数据类型相同

在这里插入图片描述

此时,我们只要修改p2中Student类中的属性值,那么p1中Student类中的属性值也会受到影响

而,当我们将Student类也进行clone重写后,Student类克隆的图解为
在这里插入图片描述

即Student对象之间不会进行相互影响

因此,我们Person类进行克隆时的图解就可以得到

在这里插入图片描述

即,我们可以想象该图就是

在这里插入图片描述

注:红色部分就是想象出来的,即是Student中的属性。现在p1和p2就不存在交集,他们的值也不会互相影响


2.3 当出现引用嵌套时

即Person中存在Student类型,而Student中又存在另一个School类型,那么要实现深克隆,则School也需要重写clone,同时在Student中对School进行特殊处理,否则它还不是一个真正的深克隆

  • 如果只处理Student,不处理School,浅克隆

在这里插入图片描述

  • Student,School都进行处理,深克隆

在这里插入图片描述

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值