clone( )方法创建调用它的对象的一个复制副本
简单地说, Clone 就是对于给定的一个对象实例 o ,得到另一个对象实例 o’ : o 与 o’ 类 型相同( o.getClass() == o’.getClass() ),内容相同(对于 o/o’ 中的字段 f ,如果 f 是基本数据类型,则 o.f == o’.f ;如果 f 是对象引用,则 o.f == o’.f 或 o.f 指向的对象与 o’.f 指向的对象的内容相同)。通常称 o’ 为 o 的克隆或副本。
当一个副本被创建时,并没有调用被复制对象的构造函数。副本仅仅是原对象的一个简单精确的拷贝。复制是一个具有潜在危险的操作,因为它可能引起不是你所期望的副作用。
例如,假如被复制的对象包含了一个称为obRef的引用变量,当副本创建时,副本中的obRef如同原对象中的obRef一样引用相同的对象。如果副本改变了被obRef引用的对象的内容,那么对应的原对象也将被改变。另一种情况,如果一个对象打开一个I/O流并被复制,两个对象将可操作相同的流。而且,如果其中一个对象关闭了流,而另一个对象仍试图对I/O流进行写操作的话,将导致错误。
protected native Object clone() throws CloneNotSupportedException;
public interface Cloneable {}
只有接口定义
看到这里可能觉得奇怪,Cloneable接口中什么都没有,要它有什么用?// Demonstrate the clone() method.
class TestClone implements Cloneable {
int a;
double b;
// This method calls Object's clone().
TestClone cloneTest() {
try {
// call clone in Object.
return (TestClone) super.clone();
} catch(CloneNotSupportedException e) {
System.out.println("Cloning not allowed.");
return this;
}
}
}
class CloneDemo {
public static void main(String args[]) {
TestClone x1 = new TestClone();
TestClone x2;
x1.a = 10;
x1.b = 20.98;
x2 = x1.cloneTest(); // clone x1
System.out.println("x1: " + x1.a + " " + x1.b);
System.out.println("x2: " + x2.a + " " + x2.b);
}
}
返回的对象必须被强制转换成它的适当类型(TestClone)。
// Override the clone() method.
class TestClone implements Cloneable {
int a;
double b;
// clone() is now overridden and is public.
public Object clone() {
try {
// call clone in Object.
return super.clone();
} catch(CloneNotSupportedException e) {
System.out.println("Cloning not allowed.");
return this;
}
}
}
class CloneDemo2 {
public static void main(String args[]) {
TestClone x1 = new TestClone();
TestClone x2;
x1.a = 10;
x1.b = 20.98;
// here, clone() is called directly.
x2 = (TestClone) x1.clone();
System.out.println("x1: " + x1.a + " " + x1.b);
System.out.println("x2: " + x2.a + " " + x2.b);
}
}
以上两种方法调用的都是Object中的clone方法,而且,java类集中很多数据结构类都有克隆功能,观察其源码,只要调用了Object中的clone()就存在文章起始处说的那些副作用
那有没有一种方式能既克隆副本,又不用担心修改副本时将原本也一并修改呢?接着看
shallow clone 和 deep clone
Object 中是shallow clone 容易出现以上说的种种问题deep clone :
public class TestClone {
/**
* @param args
*/
public static void main(String[] args) {
try {
new TestClone().cloneObject();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void cloneObject() throws CloneNotSupportedException {
Person p = new Person();
Man man = new Man();
man.setSalory("111123");
p.setName("zhangfei");
p.setMan(man);
//man.setSalory("122335");//(1)
Person pp = p.getClonePerson(p);
man.setSalory("122335");//(2)
pp.setName("aa");
System.out.println("pp.getName()= " + pp.getName() + " pp.man.getSalory()= "+pp.getMan().getSalory());
System.out.println("p.getName()=" + p.getName()+" p.man.getSalory()= "+p.getMan().getSalory());
}
}
class Person implements Cloneable {
private String name = "";
private Man man;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person getClonePerson(Person p) throws CloneNotSupportedException {
Person pp = (Person) p.clone();
return pp;
}
public Man getMan() {
return man;
}
public void setMan(Man man) {
this.man = man;
}
public Object clone() throws CloneNotSupportedException{
Person p = (Person) super.clone();
p.man = this.getMan().getCloneMan(this.getMan());
return p;
}
}
class Man implements Cloneable{
private String salory = "";
public String getSalory() {
return salory;
}
public void setSalory(String salory) {
this.salory = salory;
}
public Man getCloneMan(Man man) throws CloneNotSupportedException{
Man ma = (Man)man.clone();
return ma;
}
}
执行结果:
pp.getName()= aa pp.man.getSalory()= 111123
p.getName()=zhangfei p.man.getSalory()= 122335
大家不妨一试
(说明,以上文章结合自java.lang部分源码+内部资料+http://onlylove.iteye.com/blog/265113,如有侵权行为,速联)