2019独角兽企业重金招聘Python工程师标准>>>
这里我们就可以引入两个专业的术语:浅克隆(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);
}
}