浅复制:将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指
向的。
深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。简单来说,就是深
复制进行了完全彻底的复制,而浅复制不彻底使用原型模式创建对象比直接new一个对象在性能上要好的多,因为Object类的clone方法是一个本地方法,它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显。
使用原型模式的另一个好处是简化对象的创建,使得创建对象就像我们在编辑文档时的复制粘贴一样简单。
因为以上优点,所以在需要重复地创建相似对象时可以考虑使用原型模式。比如需要在一个循环体内创建对象,假如对象创建过程比较复杂或者循环次数很多的话,使用原型模式不但可以简化创建过程,而且可以使系统的整体性能提高很多。
/**
*
* @功能:TODO
* @版本:1.0
* @修改:
*/
public class Prototype2 implements Cloneable,Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private String string;
private int age;
private int[] ia;
public int[] getIa() {
return ia;
}
public void setIa(int[] ia) {
this.ia = ia;
}
/** 浅复制*/
public Object clone() throws CloneNotSupportedException{
Prototype2 pro = (Prototype2)super.clone();
return pro;
}
Prototype2() {
super();
// TODO Auto-generated constructor stub
}
private Prototype2(String string, int age) {
super();
this.string = string;
this.age = age;
}
/* 深复制 */
public Object deepClone() throws IOException, ClassNotFoundException {
/* 写入当前对象的二进制流 */
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();
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getString() {
return string;
}
public void setString(String string) {
this.string = string;
}
}
测试类:
public class Test {
public static void main(String[] args) throws CloneNotSupportedException, ClassNotFoundException, IOException {
Prototype2 p = new Prototype2();
p.setAge(23);
p.setString("33");
int[] a = {1,2};
p.setIa(a);
Prototype2 p1 = (Prototype2) p.clone();
System.out.println(p1.getAge());
System.out.println("Stirng: " +p.getString().hashCode());
System.out.println("Stirng: " +p1.getString().hashCode());
System.out.println(p1.getIa().hashCode());
System.out.println(p.getIa().hashCode());
System.out.println("-----------------");
Prototype2 p3 = (Prototype2) p.deepClone();
System.out.println(p3.getIa().hashCode());
System.out.println("Stirng: " +p3.getString().hashCode());
}
}
23
Stirng: 1632
Stirng: 1632
17798304
17798304
-----------------
8236034
Stirng: 1632
从上述可以看到深复制,复制 string 类型时 他的hashcode 没有改变.
String不是基本数据类型,但是在深复制的时候并没有进行单独的复制,也就是说违反了深复制,仅仅复制了引用,而String没有实现cloneable接口,也就是说只能复制引用。
那么在修改克隆之后的对象之后,会不会将原来的值也改变了?
答案肯定是不会改变,因为String是在内存中不可以被改变的对象,就比如说在for大量循环中不推荐使用+的方式来拼凑字符串一样,每次使用+都会新分配一块内存,不在原来上修改,原来的没有指向它的引用,会被回收。所以克隆相当于1个String内存空间有两个引用,当修改其中的一个值的时候,会新分配一块内存用来保存新的值,这个引用指向新的内存空间,原来的String因为还存在指向他的引用,所以不会被回收,这样,虽然是复制的引用,但是修改值的时候,并没有改变被复制对象的值