一篇文章带你了解cloneable接口、浅拷贝、深拷贝

简介: 我们都知道想要实现拷贝需要实现Cloneable接口并在类中实现clone()方法,不过比较神奇的是,clone()方法并不是Cloneable接口中的方法。Cloneable接口是一个空接口,里面没有任何内容

微信搜索《Java鱼仔》,每天一个知识点不错过


每天一个知识点


cloneable接口有什么用,浅拷贝和深拷贝你知道吗?


(一)cloneable接口有什么用


我们都知道想要实现拷贝需要实现Cloneable接口并在类中实现clone()方法,不过比较神奇的是,clone()方法并不是Cloneable接口中的方法。


Cloneable接口是一个空接口,里面没有任何内容


网络异常,图片无法展示
|


但是如果没有实现Cloneable接口,就会导致clone()方法报CloneNotSupportException错误,所以你可以把Cloneable接口看成实现clone()方法必须要的一个因素。


(二)什么是深拷贝和浅拷贝


开发过程中,有时会遇到把现有的一个对象的所有成员属性拷贝给另一个对象的需求。这个时候就会用到拷贝这个概念。我们把原对象定义成A,拷贝后的对象定义成B,如果只是单纯使用clone方法进行拷贝,你会发现:


1、对于八个基本类型,会拷贝其值,并且B的改变不会影响A。


2、如果是一个对象,拷贝的是地址引用,也就是说此时新拷贝出的对象与原有对象共享该实例变量,不受访问权限的限制。B对该值的改变会影响A。


3、对于String字符串,这个比较特殊,虽然拷贝的也是引用,但是在修改的时候,它会从字符串池中重新生成新的字符串,原有的字符串对象保持不变。


这种只单纯拷贝引用地址的动作就是浅拷贝。


相反,如果拷贝一个对象时不是简单的将地址引用拷贝出来,而是新建了一个对象,这种方式就是深拷贝。


(三)浅拷贝代码模拟


通过代码模拟浅拷贝的过程:


首先,新建两个实体类,学生和老师:


publicclassTeacher {
privateintid;
privateStringname;
//省略构造方法、get、set、toString方法}

接下来是学生,学生的实体类需要实现clone

publicclassStudentimplementsCloneable {
privateintid;
privateStringname;
privateTeacherteacher;
//省略构造方法、get、set、toString方法@OverrideprotectedObjectclone() throwsCloneNotSupportedException {
returnsuper.clone();
    }
}


网络异常,图片无法展示
|


通过结果就可以发现,修改被克隆对象的基本类型和String类型不会对原来数据造成影响,但是由于用的是同一个引用地址,修改对象时两边都会被修改。


(四)深拷贝代码模拟


深拷贝的其中一个方法是把被拷贝对象中的所有引用类型也都实现深拷贝,最后逐层拷贝实现引用地址是新的而不是用的同一个。


修改上面的teacher对象代码,实现clone方法


publicclassTeacherimplementsCloneable{
privateintid;
privateStringname;
//省略构造方法、get、set、toString方法@OverrideprotectedObjectclone() throwsCloneNotSupportedException {
returnsuper.clone();
    }
}

修改student类的clone方法

@OverrideprotectedObjectclone() throwsCloneNotSupportedException {
Studentstudent= (Student) super.clone();
student.teacher= (Teacher) teacher.clone();
returnstudent;
}

然后执行同样的测试代码后就会发现两个对象已经互相不影响了。


第二个方法是利用serializable实现深拷贝,这种方式的原理在于通过IO流的方式先将序列化后的对象写进IO流中,再取出来实现深拷贝。这种方式下所有涉及到的类都必须实现Serializable接口


新建一个DeepStudent类


publicclassDeepStudentimplementsSerializable {
privatestaticfinallongserialVersionUID=1L;
privateintid;
privateStringname;
privateTeacherteacher;
//省略构造方法、get、set、toString方法publicObjectdeepCopy(){
try {
//将对象写到IO流中ByteArrayOutputStreambos=newByteArrayOutputStream();
ObjectOutputStreamoos=newObjectOutputStream(bos);
oos.writeObject(this);
//再从IO流中获取到对象ByteArrayInputStreambis=newByteArrayInputStream(bos.toByteArray());
ObjectInputStreamois=newObjectInputStream(bis);
returnois.readObject();
        } catch (IOException|ClassNotFoundExceptione) {
e.printStackTrace();
        }
returnnull;
    }
}

编写一个测试方法:

publicstaticvoidmain(String[] args) throwsCloneNotSupportedException {
//新建一个student1DeepStudentstudent1=newDeepStudent(1,"javayz",newTeacher(1,"teacher1"));
//student2从student1中克隆过去DeepStudentstudent2= (DeepStudent) student1.deepCopy();
//修改基本类型 intstudent2.setId(2);
//修改Stringstudent2.setName("javayz2");
//修改对象类型teacherTeacherteacher=student2.getTeacher();
teacher.setName("teacher2");
System.out.println(student1);
System.out.println(student2);
    }


相关文章
|
6月前
|
存储 人工智能 前端开发
深拷贝浅拷贝的区别?如何实现一个深拷贝?
深拷贝浅拷贝的区别?如何实现一个深拷贝?
104 0
|
1月前
|
存储 前端开发 JavaScript
浅拷贝和深拷贝的区别?
本文首发于微信公众号“前端徐徐”,介绍了JavaScript中浅拷贝和深拷贝的概念及其实现方法。文章首先解释了数据类型的基础,包括原始值和对象的区别,然后详细介绍了浅拷贝和深拷贝的定义、底层逻辑以及常见的实现方式,如 `Object.assign`、扩展运算符、`JSON.stringify` 和手动实现等。最后,通过对比浅拷贝和深拷贝的区别,帮助读者更好地理解和应用这两种拷贝方式。
45 0
浅拷贝和深拷贝的区别?
|
5月前
|
安全 Java
深拷贝和浅拷贝的区别
深拷贝和浅拷贝的区别
|
6月前
|
JSON JavaScript 前端开发
深拷贝的3种常用方法
`深拷贝是一种保持数据独立性和完整性的重要手段,在许多场景下都是不可或缺的操作。
|
6月前
|
消息中间件 Kubernetes NoSQL
构造函数、深拷贝、浅拷贝
构造函数、深拷贝、浅拷贝
|
存储 JavaScript 前端开发
深拷贝浅拷贝有什么区别?怎么实现深拷贝?
深拷贝浅拷贝有什么区别?怎么实现深拷贝?
95 0
|
设计模式 Java Spring
设计模式之原型模式(Cloneable接口、浅拷贝、深拷贝)
设计模式之原型模式(Cloneable接口、浅拷贝、深拷贝)
82 0
|
JSON 数据格式
深拷贝和浅拷贝、及实现方式
深拷贝和浅拷贝、及实现方式
94 0
|
C++
C++类与对象中深拷贝与浅拷贝
C++类与对象中深拷贝与浅拷贝
67 0
|
Java
【Java】深拷贝和浅拷贝,Cloneable接口
【Java】深拷贝和浅拷贝,Cloneable接口
201 0
【Java】深拷贝和浅拷贝,Cloneable接口