拷贝对象还是拷贝引用
从上篇Java中对象的创建方式中可知clone方法被对象调用时,会复制对象,即创建了一个与源对象相同的新对象。
拷贝引用
拷贝引用并没有创建一个新的对象,两个引用的地址值是一样的,表示两个引用都指向了同一个对象。
Person p1 = new Person(1, "key");
Person p2 = p1;
拷贝对象
以下方式是真正的克隆了一个对象,两个引用的地址值是不一样的。通过“p3 == p4 ”可以验证。
Person p3 = new Person(1, "key");
Person p4 = (Person) p3.clone();
深拷贝还是浅拷贝
使用clone方法通过复制创建对象,可分为浅拷贝和深拷贝两种。
浅拷贝
如果通过clone方法拷贝的对象中的某个对象, 与源对象中对应的那个对象是同一个对象, 即只对当前对象进行了clone操作,而没有对该对象中的其他对象或更深层的对象进行clone操作,那么这就是浅拷贝。
浅拷贝的实现
只需要对当前拷贝的对象进行处理,该处理指得是:使该类实现Cloneable接口,并重写clone方法。以下两个Person对象的那么的地址值相同,则表示如果只是用Object中默认的clone方法,是浅拷贝的, 例如:
public class Person implements Cloneable{
private int id;
private String name;
public Person(int id, String name) {
this.id= id;
this.name = name;
}
public Person() {}
public int getId() {
return id;
}
public String getName() {
return name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return (Person)super.clone();
}
public static void main(String[] args){
Person p1 = new Person(1, "key");
Person p2 = (Person) p1.clone();
System.out.println(p1.getName == p2.getName);
}
}
深拷贝
与浅拷贝相对,深拷贝是指, 通过clone方法拷贝的对象中的其他所有对象, 与源对象中对应的对象不是同一个对象,即对源对象中的每个对象都进行了clone操作。
为了要在clone对象时进行深拷贝, 那么就要Clonable接口,覆盖并实现clone方法,除了调用父类中的clone方法得到新的对象, 还要将该类中的引用变量也clone出来。
如果只是用Object中默认的clone方法,是浅拷贝的
深拷贝的实现
//如果要使Body对象在clone时进行深拷贝, 那么就要在Body的clone方法中,将源对象引用的Head对象也clone一份。
static class Body implements Cloneable{
public Head head;
public Body() {}
public Body(Head head) {this.head = head;}
@Override
protected Object clone() throws CloneNotSupportedException {
Body newBody = (Body) super.clone();
newBody.head = (Head) head.clone();
return newBody;
}
}
static class Head implements Cloneable{
public Head() {}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public static void main(String[] args) throws CloneNotSupportedException {
Body body = new Body(new Head());
Body body1 = (Body) body.clone();
System.out.println("body == body1 : " + (body == body1) );
System.out.println("body.head == body1.head : " +
(body.head == body1.head));
}
注意: 如果想要深拷贝一个对象, 这个对象必须要实现Cloneable接口,实现clone方法,并且在clone方法内部,把该对象引用的其他对象也要clone一份,这就要求这个被引用的对象必须也要实现Cloneable接口并且实现clone方法。
如果在Head类中,还引用了其他对象,则必须在Head类的clone方法中将引用的对象也clone一份,才能实现深拷贝。 如果在Head类中没有再引用其他对象,则实现了完全的深拷贝。
完全的深拷贝
由深拷贝的实现,可以得知,若要实现完全的深拷贝,则在引用链上的每一级对象都要被显式的拷贝。如果其中引用了第三方库的对象,则很难实现完全的深拷贝。