Summary

浅克隆与深克隆对于JavaSE来说,是个难度系数比较低的概念,但不应该轻视它。

假设一个场景:对于某个list,代码里并没有任何对其的直接操作,但里面的元素的属性却被改变了,这可能就涉及到这个概念。

Description

浅克隆指仅copy对象位于栈内存中的引用(reference)。copy后,新旧两个引用指向同一个堆内存对象(即同一内存区域),但是堆内存中实际的对象copy前后均只有一个。使用"==" operator比较二者的地址会返回true。(不同引用,同一对象)

深克隆指则会copy一个新的对象并返回相应引用,即开辟了新的堆内存空间,因此使用“==” operator来比较两者的地址时会返回false。(不同引用,不同对象)

浅克隆(shallow clone)

  1. clone对象是实例对象时,使用“=”操作符进行浅克隆。
  2. clone对象是对象数组的元素时,使用 System.arraycoppy() 进行浅克隆。(你非得要用"=" foreach地clone也没人拦着)

jdk中显式定义的clone操作基本上都使用:

  1. System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)

例如ArrayList中的clone()、Arrays.copyOf()等对具体数组的clone其实底层都是调用该方法。

  1. package com.scv.test.clone;
  2.  
  3. public class ShallowCloneTest {
  4.  
  5. public static void main(String[] args) throws Exception {
  6. Zerg z0 = new Zerg();
  7. Zerg z1 = z0;
  8. System.out.println("0. " + (z0 == z1));//"="操作符用于对象的浅克隆
  9.  
  10. Zerg[] array0 = new Zerg[]{new Zerg(), new Zerg()};
  11. Zerg[] array1 = new Zerg[array0.length];
  12. System.arraycopy(array0, 0, array1, 0, array0.length);//System.arraycopy()用于数组的浅克隆
  13. System.out.println("1. " + (array0 == array1));
  14. for(int i = 0; i < array0.length; i++){
  15. System.out.println("Comparing element of array:" + (array0[i] == array1[i]));
  16. }
  17. }
  18.  
  19. }
  20.  
  21. class Zerg{
  22.  
  23. }
  24.  
  25. /* Output:
  26. 0. true
  27. 1. false
  28. Comparing element of array:true
  29. Comparing element of array:true
  30. */

验证Shallow Clone

深克隆(deep clone)

jdk中并没有显式定义深克隆,或者说并没有直接提供工具类来进行。要让你的自定义类支持深克隆,必须具备两个条件:

  1. implements Cloneable interface.
  2. override clone() defined in java.lang.Object.

如果不实现Cloneable而直接override Object的clone(),则会抛出CloneNotSupportedException。

  1. package com.scv.test.clone;
  2.  
  3. public class DeepCloneTest {
  4.  
  5. public static void main(String[] args) throws Exception {
  6. CloneableZerg z0 = new CloneableZerg();
  7. CloneableZerg z1 = z0.clone();
  8.  
  9. System.out.println("0. " + (z0 == z1));
  10. }
  11.  
  12. }
  13.  
  14. class CloneableZerg implements Cloneable{
  15.  
  16. @Override
  17. public CloneableZerg clone() throws CloneNotSupportedException{
  18. return (CloneableZerg)super.clone();
  19. }
  20. }
  21.  
  22. /* Output:
  23. 0. false
  24. */

验证Deep Clone

实际上,你可以自定义哪些成员变量(field)允许clone,哪些不允许(有点transient的感觉?)。

jdk中的实现:ArrayList中的浅克隆与深克隆

  1. package com.scv.test.clone;
  2.  
  3. import java.util.ArrayList;
  4.  
  5. public class ArrayListCloneTest {
  6.  
  7. public static void main(String[] args) throws Exception {
  8. CloneTarget t = new CloneTarget();
  9.  
  10. ArrayList<CloneTarget> list0 = new ArrayList<CloneTarget>(1);
  11. list0.add(t);
  12. ArrayList<CloneTarget> list1 = (ArrayList<CloneTarget>) list0.clone();
  13. list0.get(0).setFieldA(20);
  14.  
  15. System.out.println("0. " + (list0 == list1));
  16. System.out.println("1. " + (list0.get(0) == list1.get(0)));
  17. System.out.println("2. " + list1.get(0).getFieldA());
  18. }
  19.  
  20. }
  21.  
  22. class CloneTarget implements Cloneable{
  23.  
  24. private int fieldA = 10;
  25.  
  26. @Override
  27. public CloneTarget clone() throws CloneNotSupportedException{
  28. return (CloneTarget)super.clone();
  29. }
  30.  
  31. public void setFieldA(int a){
  32. fieldA = a;
  33. }
  34.  
  35. public int getFieldA(){
  36. return fieldA;
  37. }
  38. }
  39.  
  40. /*
  41. * Output:
  42. * 0. false
  43. * 1. true
  44. * 2. 20
  45. */

Click Me

操作说明:

  1. 创建一个ArrayList对象list0
  2. list0中加入一个对象t
  3. 克隆list0对象为list1
  4. 再修改list0中元素(即t)的属性

结果说明:

  1. ArrayList实现了Cloneable接口,arraylist.clone()为深克隆,故list0与list1分别指向不同内存区域。
  2. ArrayList对象的clone()对于内部数组的元素仅为浅克隆,故list0中的元素(t)与list1中的元素为同一个,对list0元素的修改将影响到list1的元素。

Java:浅克隆(shallow clone)与深克隆(deep clone)的更多相关文章

  1. java 浅克隆(浅复制)和深克隆(深复制)

    http://www.voidcn.com/blog/u011380813/article/p-6161450.html https://gold.xitu.io/entry/570d89651ea4 ...

  2. Deep Clone 常用方式总结

    Deep Clone Example 总结 Deep Clone 一般有如下几种实现方式: 纯手工每个类实现赋值 (ps: 不做介绍,一般都不想这么玩) 序列化和反序列化 纯反射 emit 或 Exp ...

  3. 深拷贝(deep clone)与浅拷贝(shallow clone)

    深拷贝(deep clone)与浅拷贝(shallow clone) 浅复制(浅克隆):被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之,浅复制仅仅复 ...

  4. java 浅克隆 深克隆

    对象的克隆是java的一项高级技术,他可以根据给定的对象,获得与其完全相同的另一个对象. 1.浅克隆主要是复制对象的值 2.深克隆:当类存在聚合关系的时候,克隆就必须考虑聚合对象的克隆,可以复制引用类 ...

  5. java浅克隆和深克隆,序列化和反序列化实现深克隆(封装序列化和反序列化操作)

    本篇博客内容: 一.浅克隆(ShallowClone)和深克隆(DeepClone) 二.序列化和反序列化实现深克隆 三.封装序列化和反序列化操作 ObjectOutputStream + 内存流By ...

  6. Ruby中如何复制对象 (deep clone)(转载)

    Ruby中如何复制对象 (deep clone) 用Ruby复制一个对象(object)也许没有你想像的那么容易. 今天我google了半天, 做个总结吧. 先从最简单的开始, b = a 是复制吗? ...

  7. JavaScript 中的对象深度复制(Object Deep Clone)

    JavaScript中并没有直接提供对象复制(Object Clone)的方法. JavaScript中的赋值,其实并不是复制对象,而是类似`c/c++`中的引用(或指针),因此下面的代码中改变对象b ...

  8. java中的Object类和其clone()

    1.Object是所有类的父类,任何类都默认继承Object,即直接或间接的继承java.lang.Object类.由于所有的类都继承在Object类,因此省略了extends Object关键字. ...

  9. What is the most efficient way to deep clone an object in JavaScript?

    What is the most efficient way to deep clone an object in JavaScript? Reliable cloning using a libra ...

随机推荐

  1. apache解压版安装服务

    解压版也就是绿色版 到apache/bin目录 然后运行下面命令 httpd.exe -k install -n "Apache24" 如果要卸载服务的话,就是下面这个命令 htt ...

  2. nwafu - java实习 JDBC练习 - 学生信息系统界面

    学生信息系统界面的实现 - JDBC writer:pprp 登录界面的实现: 分为两个部分: 1.LoginFrame.java : 用windowbuilder进行快速搭建界面,构建好登录的界面, ...

  3. wireshark抓包分析

    TCP协议首部: 分析第一个包: 源地址:我自己电脑的IP,就不放上来了 Destination: 222.199.191.33 目的地址 TCP:表明是个TCP协议 Length:66 表明包的长度 ...

  4. Python类变量,实例变量,类方法,实例方法,静态方法的分析

    Python作为动态语言,跟静态语言如c/c++有很大区别,其中的一个重要的特性就是Python的变量无需声明直接可用.同样,类的成员变量无需声明,直接可用.目的是为了动态语言跟灵活,在思路想到的时候 ...

  5. cygwin下安装软件

    cygwin下安装软件cygwin工具安装新的软件和常见的命令windows8.1下安装Cygwin并通过apt-cyg安装软件包Cygwin利用apt-cyg安装gcc.g++.make和gdb 首 ...

  6. Win7 64位安装VS2013无法连接远程数据库

    win7 64位安装vs2013后连接远程数据库出现下面的问题:A first chance exception of type 'System.AccessViolationException' o ...

  7. sql数据类型转换函数

    1.CAST()CAST (<expression> AS <data_ type>[ length ]) 2.CONVERT()CONVERT (<data_ type ...

  8. UML中的组合、聚合、关联、继承、实现、依赖

    转自:http://justsee.iteye.com/blog/808799 UML定义的关系主要有六种:依赖.类属.关联.实现.聚合和组合. 继承 指的是一个类(称为子类.子接口)继承另外的一个类 ...

  9. Docker 学习记录笔记(一)

    Docker 一些简单的命令列表docker build -t friendlyhello . # Create image using this directory's Dockerfiledock ...

  10. CentOS 7添加应用快捷方式到桌面

    以eclipse为例,编辑下面文件,复制到桌面即可. vi client.desktop [Desktop Entry]Encoding=UTF-8Name=eclipseExec=/home/clo ...