这里我们就可以引入两个专业的术语:浅克隆(shallow clone)和深克隆(deep clone)。
所谓的浅克隆,顾名思义就是很表面的很表层的克隆,如果我们要克隆Administrator对象,只克隆他自身以及他包含的所有对象的引用地址。而深克隆,就是非浅克隆。克隆除自身以外所有的对象,包括自身所包含的所有对象实例。至于深克隆的层次,由具体的需求决定,也有“N层克隆”一说。但是,所有的基本(primitive)类型数据,无论是浅克隆还是深克隆,都会进行原值克隆。毕竟他们都不是对象,不是存储在堆中。(Java中所有的对象都是保存在堆中,而堆是供全局共享的。也就是说,如果同一个Java程序的不同方法,只要能拿到某个对象的引用,引用者就可以随意的修改对象的内部数据。)
要让一个对象进行克隆,其实就是两个步骤:1. 让该类实现java.lang.Cloneable接口;2. 重写(override)Object类的clone()方法。(并且在方法内部调用持有对象的clone()方法;如果有N多个持有的对象,那就要写N多的方法,突然改变了类的结构,还要重新修改clone()方法。)
public class CloneBean implements Serializable,Cloneable{ private String st1 ; private int i; public String getSt1() { return st1; } public void setSt1(String st1) { this.st1 = st1; } public int getI() { return i; } public void setI(int i) { this.i = i; } //可以实现自身的 值克隆 ,如果在父类的克隆的时候, 显示的调用自身的克隆,并复制给 @Override public Object clone() { CloneBean cb = null; try { cb = (CloneBean) super.clone();//要调用 父类的 clone方法 } catch (CloneNotSupportedException e) { e.printStackTrace(); } return cb; } }
public class ShallowClone implements Cloneable {
// 基本类型 每个对象一份 private int a; private String b; // 非基本类型 数组 对象, 复制的对象保持一个引用,相关的修改都会影响 private int[] c; private CloneBean clonebean; // 重写Object.clone()方法,并把protected改为public 《只是浅克隆, 如果要实现真正的深克隆,用到 序列化及反序列化》 @Override public Object clone() { ShallowClone sc = null; try { sc = (ShallowClone) super.clone();//要调用 父类的 clone方法 } catch (CloneNotSupportedException e) { e.printStackTrace(); } //sc.clonebean=(CloneBean)clonebean.clone(); 显示的调用 对象的克隆,也可以保持对象的新值,因为 本身对象又是一个新的对象 return sc; }public int getA() {
return a; }public void setA(int a) {
this.a = a; }public String getB() {
return b; }public void setB(String b) {
this.b = b; }public int[] getC() {
return c; }public void setC(int[] c) {
this.c = c; }public CloneBean getClonebean() {
return clonebean; }public void setClonebean(CloneBean clonebean) {
this.clonebean = clonebean; } }
public class ShallowCloneTest {
public static void main(String[] args) throws CloneNotSupportedException { ShallowClone c1 = new ShallowClone(); // 对c1赋值 c1.setA(100); c1.setB("clone1"); c1.setC(new int[] { 1000 }); CloneBean cb = new CloneBean(); cb.setI(10); cb.setSt1("str1"); c1.setClonebean(cb);System.out.println("克隆前: c1.a=" + c1.getA());
System.out.println("克隆前: c1.b=" + c1.getB()); System.out.println("克隆前: c1.c[0]=" + c1.getC()[0]); System.out.println("克隆前: c1.cb.str1=" + c1.getClonebean().getSt1()); System.out.println("-----------");// 克隆出对象c2,并对c2的属性A,B,C进行修改
ShallowClone c2 = (ShallowClone) c1.clone(); // 对c2进行修改 c2.setA(50); c2.setB("clone2"); int[] a = c2.getC(); a[0] = 500; c2.setC(a); CloneBean cb1 = c2.getClonebean(); cb1.setSt1("tewtstewt"); c2.setClonebean(cb1);System.out.println("克隆后: c1.a=" + c1.getA());
System.out.println("克隆后: c1.b=" + c1.getB()); System.out.println("克隆后: c1.c[0]=" + c1.getC()[0]); System.out.println("克隆后: c1.cb.str1=" + c1.getClonebean().getSt1()); System.out.println("---------------");System.out.println("克隆后: c2.a=" + c2.getA());
System.out.println("克隆后: c2.b=" + c2.getB()); System.out.println("克隆后: c2.c[0]=" + c2.getC()[0]); System.out.println("克隆后: c2.cb.str1=" + c2.getClonebean().getSt1()); } }×××××××××××××××××××××用serializable来实现×××××××××××××××××××××××××××××××××××
//前提是对象以及对象内部 所有引用到的对象 都是可串行化的,否则,就需要仔细考察那些不可串行化的对象可否设成transient,从而将之排除在复制过程之外。而类变量 是全局的,也不作序列化操作。
public class DeepClone implements Serializable { private static final long serialVersionUID = -4371342386287259388L; private transient String transi;//修饰为不可瞬时的 不可序列化对象 public static int k; private int a; private String b; private int[] c; private CloneBean cb;//必须也是可串行化的 public int getA() { return a; } public void setA(int a) { this.a = a; } public String getB() { return b; } public void setB(String b) { this.b = b; } public int[] getC() { return c; } public void setC(int[] c) { this.c = c; } public CloneBean getCb() { return cb; } public void setCb(CloneBean cb) { this.cb = cb; } public String getTransi() { return transi; } public void setTransi(String transi) { this.transi = transi; } public static int getK() { return k; } public static void setK(int k) { DeepClone.k = k; }// 用序列化与反序列化实现深克隆
public Object deepClone() { Object o = null; try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(this); oos.close(); ByteArrayInputStream bais = new ByteArrayInputStream(baos .toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); o = ois.readObject(); ois.close(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return o; } } // 所有的对象 都必须 实现 序列化接口 public class DeepCloneTest { public static void main(String[] args) throws CloneNotSupportedException { DeepClone dc1 = new DeepClone(); // 对dc1赋值 dc1.setA(100); dc1.setB("clone1"); dc1.setC(new int[] { 1000 }); CloneBean cb = new CloneBean(); cb.setSt1("deepClone...before..."); dc1.setCb(cb); dc1.setTransi("transiant before"); DeepClone.k=100; System.out.println("克隆前: dc1.a=" + dc1.getA()); System.out.println("克隆前: dc1.b=" + dc1.getB()); System.out.println("克隆前: dc1.c[0]=" + dc1.getC()[0]); System.out.println("克隆前: dc1.cd.str1=" + dc1.getCb().getSt1()); System.out.println("克隆前: dc1.transiant=" + dc1.getTransi()); System.out.println("克隆前: dc1.k=" + DeepClone.k); System.out.println("-----------"); //序列化的所有对象 都要 实现 序列化接口 DeepClone dc2 = (DeepClone)dc1.deepClone(); // 对c2进行修改 dc2.setA(50); dc2.setB("clone2"); int[] a = dc2.getC(); a[0] = 500; dc2.setC(a); CloneBean cb2 = dc2.getCb(); cb2.setSt1("deepClone...after..."); dc2.setCb(cb2); System.out.println(dc2.getTransi()); //null值 没有进行复用 System.out.println(DeepClone.k); //静态代码块 不用串行化,本身就是公用一块区域 dc2.setTransi("transiant after"); DeepClone.k=200; System.out.println("克隆前: dc1.a=" + dc1.getA()); System.out.println("克隆前: dc1.b=" + dc1.getB()); System.out.println("克隆前: dc1.c[0]=" + dc1.getC()[0]); System.out.println("克隆前: dc1.cd.str1=" + dc1.getCb().getSt1()); System.out.println("克隆前: dc1.transiant=" + dc1.getTransi()); System.out.println("克隆前: dc1.k=" + DeepClone.k); System.out.println("-----------"); System.out.println("克隆后: dc2.a=" + dc2.getA()); System.out.println("克隆后: dc2.b=" + dc2.getB()); System.out.println("克隆后: dc2.c[0]=" + dc2.getC()[0]); System.out.println("克隆后: dc1.cd.str1=" + dc2.getCb().getSt1()); System.out.println("克隆后: dc2.transiant=" + dc2.getTransi()); System.out.println("克隆后: dc2.k=" + DeepClone.k); } }