理解一波概念:
浅拷贝: 除了引用指向的对象(在堆上,而引用是在栈上)不被拷贝,其余都被拷贝
深拷贝:引用所指向的堆上对象也会被拷贝一份
代码演示:
1.浅拷贝
定义一个IDCard 类:
package top.forethought.javagrammer.clone;
public class IDCard {
private String No;
private String name;
public IDCard(String no, String name) {
No = no;
this.name = name;
}
... 省略getter/setter
}
定义一个People 类,内部包含一个对IDCard 类型对象的引用
// 据说:浅拷贝,只会拷贝对象内部属性,以及引用,但是不会拷贝引用所指向的对象
// 深拷贝:也会拷贝引用指向的对象
public class People implements Cloneable {
private IDCard idCard;
@Override
protected Object clone() {
Object ob= null;
try{
ob= super.clone();
}catch ( CloneNotSupportedException e){
e.printStackTrace();
}
return ob;
}
public People(IDCard idCard) {
this.idCard = idCard;
}
... 省略getter/setter
}
测试方法:
public static void main(String[] args) {
IDCard card=new IDCard("1234","张三");
People origin=new People(card);// origin 对象的成员属性是一个
//指向 名字叫"张三" 的IDCard 类型的对象的 引用
People clone=(People)origin.clone();// 克隆origin 对象,
card.setName("李白");// 对引用指向的堆上对象做出修改
// 如果是深拷贝,clone 对象的idcard 应该是不会发生改变的(因为深度拷贝,是将引用指向的堆上对象也拷贝了一个)
System.out.println(clone.getIdCard().getName());
}
测试结果:
观察测试结果:发现 origin,clone 中的idCard 所指向的堆上对象的属性name dou发生了改变
说明这是浅拷贝!!!
同时通过**{IDCard@524}** 也可以发现这三个地方出现的idCard 都是堆上的同一个对象
{类名@JVM中对象内存地址} 是Object 类的默认toString 方法实现
但是我们是想实现深度拷贝,而不是这样的浅拷贝,应为浅拷贝会导致无论哪一个对象修改,其他对象也会跟着修改,导致对象间不是独立的关系,这对实际业务会造成蜜汁bug
2深度拷贝实现:
IDCard
public class IDCard implements Cloneable{
private String No;
private String name;
public IDCard(String no, String name) {
No = no;
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
... 省略getter/setter
}
People
public class People implements Cloneable {
private IDCard idCard;
// @Override
// protected Object clone() {
// Object ob= null;
// try{
// ob= super.clone();
// }catch ( CloneNotSupportedException e){
// e.printStackTrace();
// }
//
//
// return ob;
// }
@Override
protected Object clone() {
People obj=null;
try{
obj= (People) super.clone();
obj.idCard= (IDCard) idCard.clone();//将引用指向的对象也拷贝一份
}catch (CloneNotSupportedException e){
e.printStackTrace();
}
return obj;
}
public People(IDCard idCard) {
this.idCard = idCard;
}
... 省略getter/setter
}
测试代码同浅拷贝测试,
测试效果:
现在发现,修改原来的堆上对象,不会影响到由拷贝产生的新的对象
总结:
注意对引用类型的处理上,浅拷贝,只处理自己这个类里面的数据,比如引用类型,但是不关心引用所指向的堆上对象是啥样