对于上述的问题虽然拷贝的两个对象不同,但其内部的一些引用还是相同的,怎么样绝对的拷贝这个对象,使这个对象完全独立于原对象呢?就使用我们的深拷贝了。深拷贝:在对引用数据类型进行拷贝的时候,创建了一个新的对象,并且复制其内的成员变量。
在具体实现深拷贝上,这里提供两个方式,重写clone()方法和序列法。
重写clone()方法如果使用重写clone()方法实现深拷贝,那么要将类中所有自定义引用变量的类也去实现Cloneable接口实现clone()方法。对于字符类可以创建一个新的字符串实现拷贝。
对于上述代码,Father类实现Cloneable接口并重写clone()方法。son的clone()方法需要对各个引用都拷贝一遍。
//Father clone()方法 @Override protected Father clone() throws CloneNotSupportedException { return (Father) super.clone(); } //Son clone()方法 @Override protected Son clone() throws CloneNotSupportedException { Son son= (Son) super.clone();//待返回克隆的对象 son.name=new String(name); son.father=father.clone(); return son; }其他代码不变,执行结果如下:
Son{age=13,, father=Father{name='bigFather'}} Son{age=13,, father=Father{name='bigFather'}} s1==s2:false s1.name==s2.name:false s1.Father==s2.Father:false s1.name==s2.name:false Son{age=12,, father=Father{name='smallFather'}} Son{age=13,, father=Father{name='bigFather'}} 序列化可以发现这种方式实现了深拷贝。但是这种情况有个问题,如果引用数量或者层数太多了怎么办呢?
不可能去每个对象挨个写clone()吧?那怎么办呢?借助序列化啊。
因为序列化后:将二进制字节流内容写到一个媒介(文本或字节数组),然后是从这个媒介读取数据,原对象写入这个媒介后拷贝给clone对象,原对象的修改不会影响clone对象,因为clone对象是从这个媒介读取。
熟悉对象缓存的知道我们经常将Java对象缓存到Redis中,然后还可能从Redis中读取生成Java对象,这就用到序列化和反序列化。一般可以将Java对象存储为字节流或者json串然后反序列化成Java对象。因为序列化会储存对象的属性但是不会也无法存储对象在内存中地址相关信息。所以在反序列化成Java对象时候会重新创建所有的引用对象。
在具体实现上,自定义的类需要实现Serializable接口。在需要深拷贝的类(Son)中定义一个函数返回该类对象:
protected Son deepClone() throws IOException, ClassNotFoundException { Son son=null; //在内存中创建一个字节数组缓冲区,所有发送到输出流的数据保存在该字节数组中 //默认创建一个大小为32的缓冲区 ByteArrayOutputStream byOut=new ByteArrayOutputStream(); //对象的序列化输出 ObjectOutputStream outputStream=new ObjectOutputStream(byOut);//通过字节数组的方式进行传输 outputStream.writeObject(this); //将当前student对象写入字节数组中 //在内存中创建一个字节数组缓冲区,从输入流读取的数据保存在该字节数组缓冲区 ByteArrayInputStream byIn=new ByteArrayInputStream(byOut.toByteArray()); //接收字节数组作为参数进行创建 ObjectInputStream inputStream=new ObjectInputStream(byIn); son=(Son) inputStream.readObject(); //从字节数组中读取 return son; }使用时候调用我们写的方法即可,其他不变,实现的效果为:
Son{age=13,, father=Father{name='bigFather'}} Son{age=13,, father=Father{name='bigFather'}} s1==s2:false s1.name==s2.name:false s1.Father==s2.Father:false s1.name==s2.name:false Son{age=12,, father=Father{name='smallFather'}} Son{age=13,, father=Father{name='bigFather'}} 写在最后原创不易,bigsai我请园友帮两件事帮忙一下:
点赞支持一下, 您的肯定是我在园子创作的源源动力。
微信搜索「bigsai」,关注我的公众号(新人求支持),会第一时间在公众号分享知识技术。还可拉你进力扣打卡群一起打卡LeetCode。
记得关注、咱们下次再见!