主要是学习之后的一个梳理和总结。
clone的用法:
1.实现 Cloneable 接口。
2.重写clone()方法。
3.在方法中调用super.clone()。
稍微吐槽一下有些教学贴,一直在说重载clone()方法,也许是笔误,但我觉得还是要严谨,这里是重写。
深拷贝与浅拷贝:
浅拷贝:对基本数据类型进行值传递,对引用数据类型只是进行了引用的传递。
深拷贝:对基本数据类型进行值传递,对引用数据类型拷贝时创建了新对象,并复制其内的成员变量。
这里想多说一句,之前有看过说Java中只有值的传递,对于对象参数,值的内容是对象的引用。
举个栗子:
我要实现一个Father类,一个Son类,通过具体的场景试图理解clone()的用法以及深拷贝和浅拷贝。
/**
* @Author Max
* @Date 2019/7/6 23:46
**/
public class Father implements Cloneable {
private String name;
private int age;
private Son son;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
/* Getter and Setter */
}
/**
* @Author Max
* @Date 2019/7/6 23:46
**/
public class Son implements Cloneable {
private String name;
private int age;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
/* Getter and Setter */
}
假设有一个叫Smith的35岁爸爸,有个10岁的儿子名叫Stan,Stan有个15岁的朋友,名叫Kim,Kim的爸爸和Stan的爸爸同名而且年纪还一样。于是就有了以下代码:
Father father = new Father();
father.setName("Smith");
father.setAge(35);
Son son = new Son();
son.setName("Stan");
son.setAge(10);
father.setSon(son);
Father father1 = (Father) father.clone();
father1.getSon().setName("Kim");
father1.getSon().setAge(15);
System.out.println("father name: " + father.getName());
System.out.println("father1 name: " + father1.getName());
System.out.println("father age : " + father.getAge());
System.out.println("father1 age : " + father1.getAge());
System.out.println("father's son name: " + father.getSon().getName());
System.out.println("father1's son name: " + father1.getSon().getName());
System.out.println("father's son age : " + father.getSon().getAge());
System.out.println("father1's son age :" + father1.getSon().getAge());
然后我们通过输出来看结果:
发现第一个Smith的儿子也变成Kim了,这是怎么回事呢?我们来看一下这两个Father对象是不是同一个对象,然后再看看这两个Son对象是不是同一个对象:
System.out.println("== :" + (father == father1));
System.out.println("equals() :" + father.equals(father1));
System.out.println("father hashcode : " + father.hashCode());
System.out.println("faher1 hashcode : " + father1.hashCode());
System.out.println("=========================================");
System.out.println("father's son hashcode: " + father.getSon().hashCode());
System.out.println("father1's son hashcode: " + father1.getSon().hashCode() );
输出:
我们发现这两个father确实不是一个father了,但son却是一个son,这显然是不对的。
原来,我们在clone father的时候使用的是浅拷贝,它对于son对象没有创建一个新对象出来,所以会有问题。
那么该怎么办呢?深拷贝可以做这件事。
实际上,我们只需要在Father类的clone方法中显式地对son进行一次clone就可以了。
@Override
protected Object clone() throws CloneNotSupportedException {
Father newFather = (Father) super.clone();
newFather.setSon( (Son) this.son.clone());
return newFather;
// return super.clone();
}
然后我们就可以发现,第二个father的son也是一个新创建的对象了:
所以,当你需要一个新的引用数据类型的时候,就使用深拷贝吧。如果这个例子改成,Kim和Stan是兄弟,即他们的爸爸是同一个人,那么可以使用浅拷贝。
Son类修改如下:
public class Son implements Cloneable {
private String name;
private int age;
private Father father;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
Father类修改如下:
public class Father implements Cloneable {
private String name;
private int age;
// private Son son;
@Override
protected Object clone() throws CloneNotSupportedException {
// Father newFather = (Father) super.clone();
// newFather.setSon( (Son) this.son.clone());
// return newFather;
return super.clone();
}
测试:
Father father = new Father();
father.setName("Smith");
father.setAge(35);
Son son = new Son();
son.setName("Stan");
son.setAge(10);
son.setFather(father);
Son son2 = (Son) son.clone();
son2.setName("Kim");
son2.setAge(15);
System.out.println("son hashcode:" + son.hashCode());
System.out.println("son2 hashcode:" + son2.hashCode());
System.out.println("=========================================");
System.out.println("son name:" + son.getName());
System.out.println("son2 name:" + son2.getName());
System.out.println("son age:" + son.getAge());
System.out.println("son2 age:" + son2.getAge());
System.out.println("=========================================");
System.out.println("Son's father hashcode:" + son.getFather().hashCode());
System.out.println("Son2's father hashcode:" + son2.getFather().hashCode());
System.out.println("son's father's name:" + son.getFather().getName());
System.out.println("son2's father's name:" + son2.getFather().getName());
结果:
说了这么多,你一定和我一样理解了深拷贝和浅拷贝,以及clone()的用法了吧。