java克隆

本文详细介绍了Java中的对象复制,包括浅克隆和深克隆的概念及其区别。通过实例代码展示了如何实现浅克隆和深克隆,解释了在对象复制过程中可能出现的问题,并提供了序列化实现深克隆的方法。强调了深克隆在确保对象独立性上的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

什么是克隆

java的克隆类似于对象的复制。

为什么需要克隆

想对一个对象进行处理,且保留原有的对象。
比如根据一个叫张三的学生信息,复制出李四、王五的学生信息,且保留张三的学生信息,然后组装三个学生的List。

java克隆分类

java克隆分为浅克隆与深克隆。

  1. 浅克隆:只克隆基本类型。引用类型没有克隆,只是新建一个引用,该引用仍然指向原有的对象。比如张三的学生信息中,有老师这个引用对象。克隆张三的学生信息修改成李四的信息后,老师信息并未被克隆,修改张三的老师,李四的老师也被修改。
  2. 深克隆:基本类型和引用类型都被克隆,引用类型的变量指向的是新克隆的对象。

下面上代码实例,为了保险起见,咱们上三层嵌套。Student里有Teacher,Teacher里有Course。

浅克隆

  1. Student代码
package org.ludk.clone;

/**
 * @author ludengke
 * @title: Student
 * @projectName springcloud-demo
 * @description: TODO
 * @date 2021/10/1822:13
 */
public class Student implements Cloneable{
    private String name;
    private int age;
    private  Teacher teacher;

    public Student(String name, int age, Teacher teacher) {
        this.name = name;
        this.age = age;
        this.teacher = teacher;
    }

    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 Teacher getTeacher() {
        return teacher;
    }

    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }

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

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

  1. Teacher代码
package org.ludk.clone;

/**
 * @author ludengke
 * @title: Teacher
 * @projectName springcloud-demo
 * @description: TODO
 * @date 2021/10/1822:14
 */
public class Teacher implements Cloneable{
    private String name;
    private int age;
    private Course course;

    public Teacher(String name, int age, Course course) {
        this.name = name;
        this.age = age;
        this.course = course;
    }

    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 Course getCourse() {
        return course;
    }

    public void setCourse(Course course) {
        this.course = course;
    }

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

    @Override
    public String toString() {
        return "Teacher{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", course=" + course +
                '}';
    }
}


  1. Course代码
package org.ludk.clone;

/**
 * @author ludengke
 * @title: Course
 * @projectName springcloud-demo
 * @description: TODO
 * @date 2021/10/1822:15
 */
public class Course {
    private String name;
    private int days;

    public Course(String name, int days) {
        this.name = name;
        this.days = days;
    }

    public String getName() {
        return name;
    }

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

    public int getDays() {
        return days;
    }

    public void setDays(int days) {
        this.days = days;
    }

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

    @Override
    public String toString() {
        return "Course{" +
                "name='" + name + '\'' +
                ", days=" + days +
                '}';
    }
}


  1. 测试类代码
package org.ludk.clone;

/**
 * @author ludengke
 * @title: TestClone
 * @projectName springcloud-demo
 * @description: 克隆学习测试类
 * @date 2021/10/1719:12
 */
public class TestClone implements Cloneable{
    /**
     * main方法
     * @param args
     */
    public static void main(String[] args) throws CloneNotSupportedException {
        //新建个学生张三
        Student student=new Student("张三",24,new Teacher("王老师",40,new Course("英语",90)));
        //克隆学生
        Student cloneStudent=(Student) student.clone();
        System.out.println("学生张三和克隆学生是否为一个老师");
        System.out.println(student.getTeacher()==cloneStudent.getTeacher());
        System.out.println("学生张三和克隆学生是否为一个课程");
        System.out.println(student.getTeacher().getCourse()==cloneStudent.getTeacher().getCourse());
        System.out.println("学生张三的信息");
        System.out.println(student);
        //克隆学生的信息
        System.out.println("克隆学生的信息");
        System.out.println(cloneStudent);
    }
}


  1. 测试类执行结果
D:\work\java\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=62957:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath D:\work\java\jre\lib\charsets.jar;D:\work\java\jre\lib\deploy.jar;D:\work\java\jre\lib\ext\access-bridge-64.jar;D:\work\java\jre\lib\ext\cldrdata.jar;D:\work\java\jre\lib\ext\dnsns.jar;D:\work\java\jre\lib\ext\jaccess.jar;D:\work\java\jre\lib\ext\jfxrt.jar;D:\work\java\jre\lib\ext\localedata.jar;D:\work\java\jre\lib\ext\nashorn.jar;D:\work\java\jre\lib\ext\sunec.jar;D:\work\java\jre\lib\ext\sunjce_provider.jar;D:\work\java\jre\lib\ext\sunmscapi.jar;D:\work\java\jre\lib\ext\sunpkcs11.jar;D:\work\java\jre\lib\ext\zipfs.jar;D:\work\java\jre\lib\javaws.jar;D:\work\java\jre\lib\jce.jar;D:\work\java\jre\lib\jfr.jar;D:\work\java\jre\lib\jfxswt.jar;D:\work\java\jre\lib\jsse.jar;D:\work\java\jre\lib\management-agent.jar;D:\work\java\jre\lib\plugin.jar;D:\work\java\jre\lib\resources.jar;D:\work\java\jre\lib\rt.jar;D:\work\springcloud-demo\target\classes org.ludk.clone.TestClone
学生张三和克隆学生是否为一个老师
true
学生张三的信息
Student{name='张三', age=24, teacher=Teacher{name='王老师', age=40, course=Course{name='英语', days=90}}}
克隆学生的信息
Student{name='张三', age=24, teacher=Teacher{name='王老师', age=40, course=Course{name='英语', days=90}}}

Process finished with exit code 0


从上面的例子,可以看到学生信息被复制了,但是里面的Teacher信息仍然是一个,仍然是一个对象。

深克隆

深克隆有两种方法。一种是遇到属性为引用类型,则对该引用类型对象进行复制。另一种是用序列化实现深克隆。

第一种方法性能高些,但是实现起来复杂,因为对象里可能还嵌套对象。第二种方法实现起来简单,但是性能差些。

自定义深克隆
  1. 修改Student的clone方法
@Override
    protected Object clone() throws CloneNotSupportedException {
        Student cloneStudent= (Student)super.clone();
        cloneStudent.setTeacher((Teacher) this.getTeacher().clone());
        return cloneStudent;
    }
  1. 再次跑测试类的结果
D:\work\java\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=50882:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath D:\work\java\jre\lib\charsets.jar;D:\work\java\jre\lib\deploy.jar;D:\work\java\jre\lib\ext\access-bridge-64.jar;D:\work\java\jre\lib\ext\cldrdata.jar;D:\work\java\jre\lib\ext\dnsns.jar;D:\work\java\jre\lib\ext\jaccess.jar;D:\work\java\jre\lib\ext\jfxrt.jar;D:\work\java\jre\lib\ext\localedata.jar;D:\work\java\jre\lib\ext\nashorn.jar;D:\work\java\jre\lib\ext\sunec.jar;D:\work\java\jre\lib\ext\sunjce_provider.jar;D:\work\java\jre\lib\ext\sunmscapi.jar;D:\work\java\jre\lib\ext\sunpkcs11.jar;D:\work\java\jre\lib\ext\zipfs.jar;D:\work\java\jre\lib\javaws.jar;D:\work\java\jre\lib\jce.jar;D:\work\java\jre\lib\jfr.jar;D:\work\java\jre\lib\jfxswt.jar;D:\work\java\jre\lib\jsse.jar;D:\work\java\jre\lib\management-agent.jar;D:\work\java\jre\lib\plugin.jar;D:\work\java\jre\lib\resources.jar;D:\work\java\jre\lib\rt.jar;D:\work\springcloud-demo\target\classes org.ludk.clone.TestClone
学生张三和克隆学生是否为一个老师
false
学生张三的信息
Student{name='张三', age=24, teacher=Teacher{name='王老师', age=40, course=Course{name='英语', days=90}}}
克隆学生的信息
Student{name='张三', age=24, teacher=Teacher{name='王老师', age=40, course=Course{name='英语', days=90}}}

Process finished with exit code 0

其实上面的自定义深克隆方法只是深克隆了老师的信息,课程的信息依然为浅克隆。可以自己实现,继续扩展。

java序列化实现深克隆
  1. Teacer、Student、Course都得实现java.io.Serializable接口
  2. 修改Student的clone方法
 @Override
    protected Object clone() throws CloneNotSupportedException {
        Student cloneObj = null;
        try {
            // 写入字节流
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            ObjectOutputStream obs = new ObjectOutputStream(out);
            obs.writeObject(this);
            obs.close();
            // 分配内存,写入原始对象,生成新对象
            ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(ios);
            // 返回生成的新对象
            cloneObj = (Student) ois.readObject();
            ois.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return cloneObj;
    }
  1. 重新跑测试类的结果
D:\work\java\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=55660:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath D:\work\java\jre\lib\charsets.jar;D:\work\java\jre\lib\deploy.jar;D:\work\java\jre\lib\ext\access-bridge-64.jar;D:\work\java\jre\lib\ext\cldrdata.jar;D:\work\java\jre\lib\ext\dnsns.jar;D:\work\java\jre\lib\ext\jaccess.jar;D:\work\java\jre\lib\ext\jfxrt.jar;D:\work\java\jre\lib\ext\localedata.jar;D:\work\java\jre\lib\ext\nashorn.jar;D:\work\java\jre\lib\ext\sunec.jar;D:\work\java\jre\lib\ext\sunjce_provider.jar;D:\work\java\jre\lib\ext\sunmscapi.jar;D:\work\java\jre\lib\ext\sunpkcs11.jar;D:\work\java\jre\lib\ext\zipfs.jar;D:\work\java\jre\lib\javaws.jar;D:\work\java\jre\lib\jce.jar;D:\work\java\jre\lib\jfr.jar;D:\work\java\jre\lib\jfxswt.jar;D:\work\java\jre\lib\jsse.jar;D:\work\java\jre\lib\management-agent.jar;D:\work\java\jre\lib\plugin.jar;D:\work\java\jre\lib\resources.jar;D:\work\java\jre\lib\rt.jar;D:\work\springcloud-demo\target\classes org.ludk.clone.TestClone
学生张三和克隆学生是否为一个老师
false
学生张三和克隆学生是否为一个课程
false
学生张三的信息
Student{name='张三', age=24, teacher=Teacher{name='王老师', age=40, course=Course{name='英语', days=90}}}
克隆学生的信息
Student{name='张三', age=24, teacher=Teacher{name='王老师', age=40, course=Course{name='英语', days=90}}}

Process finished with exit code 0

从上面的例子可以看到,java序列化实现深克隆,那是真的深克隆。

参考

下面是引用https://www.cnblogs.com/xzwblog/p/7230788.html博客的图片

  • 浅克隆

在这里插入图片描述

  • 深克隆
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值