一、clone方法简介
含义:顾名思义,克隆就是复制的意思。调用clone方法时,首先会分配一个和源对象同样大小的空间,然后再这个空间中创建新对象。
Java中创建新对象的方式有两种:new 和 clone
那么,它们有什么区别:
- new : 执行到new操作符时,会根据后面类型分配相应大小的空间,然后通过构造函数填充各个域,我们称之为初始化。
- clone:调用clone方法时,与new一样首先分配一个和源对象相同的空间,然后使用源对象中的各个域来填充新对象的域。
同样的,在new和clone在内存中创建新对象后,都会将对象的引用发布到外部。
代码实测:
1.复制引用
public static void main(String[] args) {
Dog d = new Dog("black",5,30);
Dog d1 = d;
System.out.println(d);
System.out.println(d1);
}
输出结果:
Dog@2a139a55
Dog@2a139a55
其内存情况如下:
2.复制对象
public static void main(String[] args) throws CloneNotSupportedException {
Dog d = new Dog("black",5,30);
Dog d1 = (Dog)d.clone();
System.out.println(d);
System.out.println(d1);
}
输出结果:
Dog@2a139a55
Dog@15db9742
我们看到,两个对象的地址不一样,因为通过clone后,创建了一个新的对象,而不是把源对象的地址赋给了新的引用变量。
其内存情况如下:
二、深拷贝和浅拷贝
区别:
上图中,我们看到:
浅拷贝:新对象的color属性指向源对象color属性的地址,其他属性复制了一份新的。
深拷贝:新对象的color属性指向一个新的字符串对象,其他属性复制了一份新的。
那么,clone是深拷贝or浅拷贝?
Dog实例:
public class Dog implements Cloneable{
private int weight;
private Head head;
public Dog(Head head, int weight) {
this.weight = weight;
this.head = new Head();
}
static class Head{
private Face face;
}
static class Face{
}
}
测试代码:
public static void main(String[] args) throws CloneNotSupportedException {
Dog d = new Dog(new Head(),5);
Dog d1 = (Dog)d.clone();
System.out.println(d.getHead());
System.out.println(d1.getHead());
}
输出结果:
Dog$Head@2a139a55
Dog$Head@2a139a55
从输出结果看,clone属于浅拷贝。
那么,如何实现深拷贝呢?我们可以通过重写clone方法,将Dog中的Head对象也进行clone,注意要进行clone该类要实现Cloneable接口。
public class Dog implements Cloneable{
private int weight;
private Head head;
public Dog(Head head, int weight) {
this.weight = weight;
this.head = head;
}
public Object clone() throws CloneNotSupportedException{
Dog newDog = (Dog)super.clone();
newDog.head = (Head)head.clone();
return newDog;
}
static class Head implements Cloneable{
private Face face;
public Head(){
face = new Face();
}
public Face getFace() {
return face;
}
public void setFace(Face face) {
this.face = face;
}
public Object clone() throws CloneNotSupportedException{
return super.clone();
}
}
static class Face{
}
}
测试代码:
public static void main(String[] args) throws CloneNotSupportedException {
Dog d = new Dog(new Head(),5);
Dog d1 = (Dog)d.clone();
System.out.println(d.getHead());
System.out.println(d1.getHead());
}
输出结果:
Dog$Head@2a139a55
Dog$Head@15db9742
从结果中,看出对象进行了深拷贝。那么,这里进行的深拷贝是彻底的吗?
测试代码(同上例子,这次我我们打印Head对象中的Face对象)
public static void main(String[] args) throws CloneNotSupportedException {
Dog d = new Dog(new Head(),5);
Dog d1 = (Dog)d.clone();
System.out.println(d.getHead().getFace());
System.out.println(d1.getHead().getFace());
}
输出结果:
Dog$Face@2a139a55
Dog$Face@2a139a55
由深拷贝的原理得知,我们要继续彻底的对Dog进行拷贝,就要在Head对象中继续重写clone方法,将Face进行clone,
这里理解了的朋友就会问:要是Face对象中还有一个Eye对象呢?
没错,这个时候要彻底的拷贝,就要继续在Face中重写Clone方法,将Eye进行拷贝,这样的话是不是没有真正意义上的彻底的深拷贝呢?
理论上是这样的,但是在我们实际开发中,基本上不会碰到真样的情况的。我们只要理解浅拷贝和深拷贝的原理即可。