在实际编程过程中,我们常常要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能会需要一个和A完全相同新对象B,并且此后对B任何改动都不会影响到A中的值,也就是说,A与B是两个独立的对象,但B的初始值是由A对象确定的。在这种情况下常常使用clone。当然你完全可以new一个新的,让后再进行赋值。但应用clone会有如下的好处:
1、实现clone方法比较简单、方便。
2、Object类的clone()一个native方法,native方法的效率一般来说都是远高于java中的非native方法,因此clone方法是高效的。
注意;通过序列化的方式也可以实现clone。如果一个对象包含复杂类型的变量时,可用序列化或深度clone来实现对象的clone。
浅度复制和深度复制
在java中,对于基本类型的数据可采用浅度复制的方式进行对象的复制,其中做法就是直接继承Cloneable接口,调用Object类的clone()方法就可以了。而对于非基本类型的数据,复制方法只能采用深度复制或序列化的方式进行复制。 典型的实例:/**
*
* @功能 羊对象类
* @创建人 gao_jie
* @创建日期 Jun 25, 2009
* @版本 1.0
*
*/
public class Sheep implements Cloneable {
private String name;//名字
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/* (non-Javadoc)
* @see java.lang.Object#clone()
*/
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Sheepfold implements Cloneable {
public Sheep sheep;//羊对象
public String name;//羊圈名字
public int number;//数量
public Sheepfold() {
this.sheep = new Sheep();
}
/* (non-Javadoc)
* @see java.lang.Object#clone()
*/
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Test {
public static void main(String[] args) {
// 声明一个小羊圈对象
Sheepfold smallFold = new Sheepfold();
smallFold.name = "小羊圈";
smallFold.number = 10;
smallFold.sheep.setName("小羊");
// 复制羊圈
Sheepfold bigFold = null;
try {
bigFold = (Sheepfold) smallFold.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
bigFold.name="大羊圈";
bigFold.number=100;
bigFold.sheep.setName("大羊");
System.out.println("小羊圈输出信息如下:");
System.out.println("smallFold.name="+smallFold.name);
System.out.println("smallFold.number="+smallFold.number);
System.out.println("smallFold.sheep="+smallFold.sheep.getName());
System.out.println("大羊圈输出信息如下:");
System.out.println("bigFold.name="+bigFold.name);
System.out.println("bigFold.number="+bigFold.number);
System.out.println("bigFold.sheep="+bigFold.sheep.getName());
}
}
测试结果:
小羊圈输出信息如下:
smallFold.name=小羊圈
smallFold.number=10
smallFold.sheep=大羊
大羊圈输出信息如下:
bigFold.name=大羊圈
bigFold.number=100
bigFold.sheep=大羊
显然上面的这种复制是失败的,因为改动第二个对象中的名字后第一个对象的名字也发生了变化。要实现正确的复制,必须采用深度复制。其sheepfold类中clone方法的代码应改为如下:
把上面的例子改成深度clone很简单,只需将Sheepfold的clone()方法改为如下即可:
public Object clone() throws CloneNotSupportedException {
Sheepfold fold = (Sheepfold)super.clone();
sheep = (Sheep)fold.sheep.clone();
return fold;
}
另外,采用序列化也可以实现深度复制的效果。
代码如下:
/**
*
* @功能 羊对象类
* @创建人 gao_jie
* @创建日期 Jun 25, 2009
* @版本 1.0
*
*/
public class Sheep implements Serializable{
private String name;//名字
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Sheepfold implements Cloneable, Serializable {
public Sheep sheep;// 羊对象
public String name;// 羊圈名字
public int number;// 数量
public Sheepfold() {
this.sheep = new Sheep();
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#clone()
*/
public Object clone() throws CloneNotSupportedException {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
// 将流序列化
ByteArrayInputStream bis = new ByteArrayInputStream(bos
.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
测试类
public class Test {
public static void main(String[] args) {
// 声明一个小羊圈对象
Sheepfold smallFold = new Sheepfold();
smallFold.name = "小羊圈";
smallFold.number = 10;
smallFold.sheep.setName("小羊");
// 复制羊圈
Sheepfold bigFold = null;
try {
bigFold = (Sheepfold) smallFold.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
bigFold.name="大羊圈";
bigFold.number=100;
bigFold.sheep.setName("大羊");
System.out.println("小羊圈输出信息如下:");
System.out.println("smallFold.name="+smallFold.name);
System.out.println("smallFold.number="+smallFold.number);
System.out.println("smallFold.sheep="+smallFold.sheep.getName());
System.out.println("大羊圈输出信息如下:");
System.out.println("bigFold.name="+bigFold.name);
System.out.println("bigFold.number="+bigFold.number);
System.out.println("bigFold.sheep="+bigFold.sheep.getName());
}
}
测试结果:
小羊圈输出信息如下:
smallFold.name=小羊圈
smallFold.number=10
smallFold.sheep=小羊
大羊圈输出信息如下:
bigFold.name=大羊圈
bigFold.number=100
bigFold.sheep=大羊
显然,序列化可以实现深度复制的效果,但每个非基本类型对象都必须是可序列化的。而设计模式中的原型啊模式也就是实现深度复制,因此,原型模式可以采用深度复制和序列化两种方式来实现。