Cloneable接口及clone()

本文详细介绍了Java中的克隆机制,包括Cloneable接口的作用、如何实现浅克隆和深克隆,以及深克隆的具体实现案例。通过序列化和反序列化的方法实现对象及其内部引用类型成员的完全复制。

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

Cloneable接口中不包含任何的方法!

Cloneable接口的作用:

    Object类中的clone()是protected的方法,在没有重写Object的clone()方法且没有实现Cloneable接口的实例上调用clone方法,会报CloneNotSupportedException异常。

    实现Cloneable接口仅仅是用来指示Object类中的clone()方法可以用来合法的进行克隆,即实现了Cloneable接口在调用Object的clone方法时不会再报CloneNotSupportedException异常。 

clone方法:

    类在重写clone方法的时候,要把clone方法的属性设置为public。

克隆

为什么需要克隆?

    在实际编程过程中,会需要创建与已经存在的对象A的值一样的对象B,但是是与A完全独立的一个对象,即对两个对象做修改互不影响,这时需要用克隆来创建对象B。通过new一个对象,然后各个属性赋值,也能实现该需求,但是clone方法是native方法,native方法的效率一般远高于非native方法(待了解)。

浅克隆

    对于Object类中的clone()方法产生的效果是:现在内存中开辟一块和原始对象一样的内存空间,然后原样拷贝原始对象中的内容。对基本数据类型来说,这样的操作不会有问题,但是对于非基本类型的变量,保存的仅仅是对象的引用,导致clone后的非基本类型变量和原始对象中相应的变量指向的是同一个对象,对非基本类型的变量的操作会相互影响。

结论:

1、克隆一个对象不会调用对象的构造方法。

2、clone()方法有三条规则:1)x.clone() != x; 2)x.clone().getClass() == x.getClass(); 3)一般情况下x.clone().equals(x); 3)不是必须要满足的。

3、对对象基本数据类型的修改不会互相影响,浅克隆对对象非基本数据类型的修改会相互影响,所以需要实现深克隆。

深克隆

    深克隆除了克隆自身对象,还对其非基本数据类型的成员变量克隆一遍。

深克隆的步骤:

1、首先克隆的类要实现Cloneable接口和重写Object的clone()方法。

2、在不引入第三方jar包的情况下,可以使用两种方法:1)先对对象进行序列化,紧接着马上反序列化 2)先调用super.clone()方法克隆出一个新对象,然后手动给克隆出来的对象的非基本数据类型的成员变量赋值。

    在数据结构比较复杂的情况下,序列化和反序列化可能实现起来简单,方法2)实现比较复杂。经测试2)会比1)的执行效率高。

 

序列化实现深克隆的例子

package com.zxy.java.lang;

import java.io.Serializable;

/**
 * @author
 * @version 1.0
 * description:Student类,Teacher类中的成员变量类型,也需要实现序列化
 * date: 2018-06-29 15:04
 */
public class Student implements Serializable{
    private String id;
    private String name;

    public Student(String id, String name) {
        this.id = id;
        this.name = name;
    }

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

    public String getName() {

        return name;
    }

    public void setId(String id) {

        this.id = id;
    }

    public String getId() {

        return id;
    }

}
package com.zxy.java.lang;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @author
 * @version 1.0
 * description:Teacher类,用序列化和反序列化实现深克隆,clone方法中对象写到内存中,再从内存中读出
 * date: 2018-06-29 15:26
 */
public class Teacher implements Serializable, Cloneable{
    private String tid; //教工编码
    private String name; //姓名
    private List<Student> student; //学生

    public void setTid(String tid) {
        this.tid = tid;
    }

    public String getTid() {

        return tid;
    }

    public void setStudent(List<Student> student) {

        this.student = student;
    }

    public List<Student> getStudent() {

        return student;
    }

    public void setName(String name) {

        this.name = name;
    }

    public String getName() {

        return name;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        Object t = null;

        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(this);

            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            t = ois.readObject();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e2) {
            e2.printStackTrace();
        }
        return t;
    }

    public static void main(String[] args) throws CloneNotSupportedException{
        Teacher teacher = new Teacher();
        teacher.setTid("111");
        teacher.setName("张**");
        List<Student> stus = new ArrayList<>();
        Student student = new Student("001", "朱**");
        stus.add(student);
        teacher.setStudent(stus);

        Teacher teacher1 = (Teacher) teacher.clone();
        System.out.println(teacher1.getName());
        System.out.println(teacher1.getTid());
        List<Student> ss = teacher1.getStudent();
        Student s = ss.get(0);
        s.setId("002");
        s.setName("朱**222");
        System.out.println(teacher.getStudent().get(0).getId() + "-" + teacher.getStudent().get(0).getName());
        System.out.println(teacher1.getStudent().get(0).getId() + "-" + teacher1.getStudent().get(0).getName());

    }
}

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值