热门标签 | 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



推荐阅读
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • 学习Java异常处理之throws之抛出并捕获异常(9)
    任务描述本关任务:在main方法之外创建任意一个方法接收给定的两个字符串,把第二个字符串的长度减1生成一个整数值,输出第一个字符串长度是 ... [详细]
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • springmvc学习笔记(十):控制器业务方法中通过注解实现封装Javabean接收表单提交的数据
    本文介绍了在springmvc学习笔记系列的第十篇中,控制器的业务方法中如何通过注解实现封装Javabean来接收表单提交的数据。同时还讨论了当有多个注册表单且字段完全相同时,如何将其交给同一个控制器处理。 ... [详细]
  • 猜字母游戏
    猜字母游戏猜字母游戏——设计数据结构猜字母游戏——设计程序结构猜字母游戏——实现字母生成方法猜字母游戏——实现字母检测方法猜字母游戏——实现主方法1猜字母游戏——设计数据结构1.1 ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
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社区 版权所有