热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Java对象浅克隆、深克隆及序列化

2019独角兽企业重金招聘Python工程师标准这里我们就可以引入两个专业的术语:浅克隆(shallowclone)和深克隆

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

这里我们就可以引入两个专业的术语:浅克隆(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);
    }
}

 


转:https://my.oschina.net/u/1182621/blog/146371



推荐阅读
author-avatar
zulaka_208
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有