Java clone
原型模式用一个已经创建的实例作为原型,通过复制(clone
)该原型对象来创建一个和原型对象相同的新对象。Java中对象克隆需要重写Object.clone()
方法,并实现Cloneable
接口。
浅克隆
浅克隆仅仅克隆本对象,而不复制它所引用的对象。即在堆中新建一个对象,但是对象中的属性(基础类型、引用类型)都仅执行值复制。而引用类型的值是其在堆中的地址,这就造成了:引用类型x,y
满足x != x.clone()
但x.y = x.clone().y
。
默认重写Object.clone()
方法如下,实现的是浅克隆:
class B {
}
class A implements Cloneable {
public B b;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone(); // 这里完成了新建对象,并返回对象地址
}
}
在上述情况下,执行结果如下:
A a = new A();
a.b = new B();
System.out.println(a); // org.example.clone.A@1b6d3586
System.out.println(a.b); // org.example.clone.B@4554617c
System.out.println();
A clonedA = (A) a.clone();
System.out.println(clonedA); // org.example.clone.A@74a14482
System.out.println(clonedA.b); // org.example.clone.B@4554617c
深克隆
与浅克隆不同,深克隆会对引用类型再执行克隆操作。
深克隆需要自己实现。在浅客隆中使用的是默认重写,直接返回super.clone()
,这样保证返回了新对象,但不修改新对象内的引用值。深克隆就是在此基础上去手动修改新对象内的引用值,即执行其clone()
方法。
注意被引用的类型也需要重写
Object.clone()
方法并实现Clonable
接口。
class A implements Cloneable {
public B b;
@Override
protected Object clone() throws CloneNotSupportedException {
A newA = (A) super.clone();
newA.b = (B) b.clone();
return newA;
}
}
class B implements Cloneable {
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
上述代码执行,符合预期:
A a = new A();
a.b = new B();
System.out.println(a); // org.example.clone.A@1b6d3586
System.out.println(a.b); // org.example.clone.B@4554617c
System.out.println();
A clonedA = (A) a.clone();
System.out.println(clonedA); // org.example.clone.A@74a14482
System.out.println(clonedA.b); // org.example.clone.B@1540e19d
上述是两层对象的情况,对于更多层对象(a.b.c.d)的情况处理方式也一致。