基于序列化存取实现java对象深度克隆的方法详解
2023-06-13 09:14:54 时间
我们知道,在java中,将一个非原型类型类型的对象引用,赋值给另一个对象的引用之后,这两个引用就指向了同一个对象,如:
复制代码代码如下:
publicclassDeepCloneTest{
privateclassCloneTest{
privateLongmyLong=newLong(1);
}
publicstaticvoidmain(Stringargs[]){
newDeepCloneTest().Test();
}
publicvoidTest(){
CloneTestct1=newCloneTest();
CloneTestct2=ct1;
//toseeifct1andct2areonesamereference.
System.out.println("ct1:"+ct1);
System.out.println("ct2:"+ct2);
//ifct1andct2pointtoonesameobject,thenct1.myLong==ct2.myLong.
System.out.println("ct1.myLong:"+ct1.myLong);
System.out.println("ct2.myLong:"+ct2.myLong);
//wechangect2"smyLong
ct2.myLong=2L;
//toseewhetherct1"smyLongwaschanged.
System.out.println("ct1.myLong:"+ct1.myLong);
System.out.println("ct2.myLong:"+ct2.myLong);
}
}
output:
ct1:DeepCloneTest$CloneTest@c17164
ct2:DeepCloneTest$CloneTest@c17164
ct1.myLong:1
ct2.myLong:1
ct1.myLong:2
ct2.myLong:2
这个很easy,估计学java的都知道(不知道的是学java的么?)。
在内存中,对象的引用存放在栈中,对象的数据,存放在堆中,栈中的引用指向了堆中的对象。这里就是两个栈中的引用,指向了堆中的同一个对象,所以,当改变了ct2的myLong,可以看到,ct1的myLong值也随之改变,如果用图来表示,就很容易理解了:
大多时候,我们会用java语言的这一特性做我们想做的事情,比如,将对象的引用作为入参传入一个方法中,在方法中,对引用所指对象做相应修改。但有时,我们希望构造出一个和已经存在的对象具有完全相同的内容,但引用不同的对象,为此,可以这样做:
publicclassDeepCloneTest{
//mustimplementsCloneable.
privateclassCloneTestimplementsCloneable{
privateObjecto=newObject();
publicCloneTestclone(){
CloneTestct=null;
try{
ct=(CloneTest)super.clone();
}catch(CloneNotSupportedExceptione){
e.printStackTrace();
}
returnct;
}
}
publicstaticvoidmain(Stringargs[]){
newDeepCloneTest().Test();
}
publicvoidTest(){
CloneTestct1=newCloneTest();
CloneTestct2=ct1.clone();
//toseeifct1andct2areonesamereference.
System.out.println("ct1:"+ct1);
System.out.println("ct2:"+ct2);
//whetherct1.o==ct2.o?yes
System.out.println("ct1.o"+ct1.o);
System.out.println("ct1.o"+ct1.o);
}
}
output:
ct1:DeepCloneTest$CloneTest@c17164
ct2:DeepCloneTest$CloneTest@1fb8ee3
ct1.ojava.lang.Object@61de33
ct1.ojava.lang.Object@61de33
从输出可以看出:ct1和ct2确实是两个不同的引用,所以我们想当然的认为,ct1.o和ct2.o也是两个不同的对象了,但从输出可以看出并非如此!ct1.o和ct2.o是同一个对象!原因在于,虽然用到了克隆,但上面只是浅度克隆,用图形来表示:
看到上面的o了么?其实是两个对象共享的。这就相当于,你本来有一个羊圈1,里面有一只羊,然后你又弄了一个羊圈2,在不将羊从羊圈1里牵出来的情况下,将羊也圈在了羊圈2中,你以为你有两条羊了,其实呢?大家都知道。
importjava.io.ByteArrayInputStream;
importjava.io.ByteArrayOutputStream;
importjava.io.IOException;
importjava.io.ObjectInputStream;
importjava.io.ObjectOutputStream;
importjava.io.Serializable;
publicclassDeepCloneTest{
//mustimplementsCloneable.
privateclassCloneTestimplementsSerializable{
privatestaticfinallongserialVersionUID=1L;
privateObjecto=newObject();
publicCloneTestdeepClone(){
CloneTestct=null;
try{
ByteArrayOutputStreambaos=newByteArrayOutputStream();
ObjectOutputStreamoos=newObjectOutputStream(baos);
oos.writeObject(this);
ByteArrayInputStreambais=newByteArrayInputStream(baos.toByteArray());
ObjectInputStreamois=newObjectInputStream(bais);
ct=(CloneTest)ois.readObject();
}catch(IOExceptione){
e.printStackTrace();
}catch(ClassNotFoundExceptione){
e.printStackTrace();
}
returnct;
}
}
publicstaticvoidmain(Stringargs[]){
newDeepCloneTest().Test();
}
publicvoidTest(){
CloneTestct1=newCloneTest();
CloneTestct2=ct1.deepClone();
//toseeifct1andct2areonesamereference.
System.out.println("ct1:"+ct1);
System.out.println("ct2:"+ct2);
//whetherct1.o==ct2.o?no
System.out.println("ct1.o"+ct1.o);
System.out.println("ct1.o"+ct1.o);
}
}
这个时候,内存中的数据就是这样的了:
克隆任务完成。
相关文章
- java 把对象转成map_Java对象转换成Map[通俗易懂]
- java 四舍五入运算_JAVA正确的四舍五入方法「建议收藏」
- java queue toarray_Java PriorityBlockingQueue toArray()用法及代码示例
- java 怎样卸载一个类_Java 动态卸载类[通俗易懂]
- java中打印数组的方法_Java数组方法–如何在Java中打印数组
- java中static关键字的作用_Java:Java中static关键字作用
- ringbuffer java例子_Java RingBuffer.publish方法代碼示例「建议收藏」
- Java对象拷贝_对象的拷贝有几种方法
- JAVA遍历数组的三种方法_java遍历object数组
- java对象转json字符串方法_java json字符串转对象
- java json对象和json字符串互转的方法_java json转字符串
- Java获取/resources目录下的资源文件方法
- 四种不同的方法创建java对象详解编程语言
- Java之所有对象的公用方法>10.Always override toString详解编程语言
- 数据库Java连接MySQL数据库实现数据添加(java添加mysql)
- 运行Linux中定时运行Java程序的实用方法(linux定时java)
- 进程Linux下创建多个Java进程的简易方法(linux 多个java)
- Java和Redis的配合安装方法(java redis安装)
- Java应用在Linux上乱码的原因及解决方法(java linux乱码)
- java编译时出现使用了未经检查或不安全的操作解决方法
- Java权重随机的实现方法