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操作基本上都使用:

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

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

 package com.scv.test.clone;

 public class ShallowCloneTest {

     public static void main(String[] args) throws Exception {
Zerg z0 = new Zerg();
Zerg z1 = z0;
System.out.println("0. " + (z0 == z1));//"="操作符用于对象的浅克隆 Zerg[] array0 = new Zerg[]{new Zerg(), new Zerg()};
Zerg[] array1 = new Zerg[array0.length];
System.arraycopy(array0, 0, array1, 0, array0.length);//System.arraycopy()用于数组的浅克隆
System.out.println("1. " + (array0 == array1));
for(int i = 0; i < array0.length; i++){
System.out.println("Comparing element of array:" + (array0[i] == array1[i]));
}
} } class Zerg{ } /* Output:
0. true
1. false
Comparing element of array:true
Comparing element of array:true
*/

验证Shallow Clone

深克隆(deep clone)

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

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

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

 package com.scv.test.clone;

 public class DeepCloneTest {

     public static void main(String[] args) throws Exception {
CloneableZerg z0 = new CloneableZerg();
CloneableZerg z1 = z0.clone(); System.out.println("0. " + (z0 == z1));
} } class CloneableZerg implements Cloneable{ @Override
public CloneableZerg clone() throws CloneNotSupportedException{
return (CloneableZerg)super.clone();
}
} /* Output:
0. false
*/

验证Deep Clone

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

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

 package com.scv.test.clone;

 import java.util.ArrayList;

 public class ArrayListCloneTest {

     public static void main(String[] args) throws Exception {
CloneTarget t = new CloneTarget(); ArrayList<CloneTarget> list0 = new ArrayList<CloneTarget>(1);
list0.add(t);
ArrayList<CloneTarget> list1 = (ArrayList<CloneTarget>) list0.clone();
list0.get(0).setFieldA(20); System.out.println("0. " + (list0 == list1));
System.out.println("1. " + (list0.get(0) == list1.get(0)));
System.out.println("2. " + list1.get(0).getFieldA());
} } class CloneTarget implements Cloneable{ private int fieldA = 10; @Override
public CloneTarget clone() throws CloneNotSupportedException{
return (CloneTarget)super.clone();
} public void setFieldA(int a){
fieldA = a;
} public int getFieldA(){
return fieldA;
}
} /*
* Output:
* 0. false
* 1. true
* 2. 20
*/

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. [译]JavaScript需要类吗?

    [译]JavaScript需要类吗?   原文:http://www.nczonline.net/blog/2012/10/16/does-javascript-need-classes/ 译者注:在 ...

  2. asp.net core 发布 不打包cshtml 文件

    需要在 FolderProfile.pubxml 文件中添加 FolderProfile.pubxml <MvcRazorCompileOnPublish>false</MvcRaz ...

  3. [PyTorch]PyTorch/python常用语法/常见坑点

    目录 1. make_grid() 2. join与os.path.join() 3. 读文件写文件 4. json操作 5. tensorboard使用 6. python shutil.move ...

  4. Docker 推送镜像到 阿里Docker镜像

    登录 阿里云Docker镜像 https://cr.console.aliyun.com 创建一个镜像 成功之后点击  “管理” 阿里有详细的 使用说明 PS : 注意的地方是 sudo docker ...

  5. jQuery实际案例④——360导航图片效果

    如图:①首先使用弹性盒子布局display:flex; flex-wrap:wrap; ②鼠标移上去出现“百度一下,你就知道了”,这句话之前带上各个网站的logo:③logo使用的是sprite,需要 ...

  6. (转)SQL一次性插入大量数据

    在SQL Server 中插入一条数据使用Insert语句,但是如果想要批量插入一堆数据的话,循环使用Insert不仅效率低,而且会导致SQL一系统性能问题.下面介绍SQL Server支持的两种批量 ...

  7. 修改linux系统用户最大线程数限制

    linux系统对线程数量有个最大限制,当达到系统限制的最大线程数时使用账号密码ssh到系统时是无法登陆的,会报Write failed: Broken pipe,或者是shell request fa ...

  8. Linux命令 ls -l 输出内容含义详解

    Linux命令 ls -l s输出内容含义详解   1. ls  只显示文件名或者文件目录 2. ls -l(这个参数是字母L的小写,不是数字1) 用来查看详细的文件资料 在某个目录下键入ls -l可 ...

  9. python 调用接口

    这个比较乱,抽口再修改一下. 工作需要调有赞API的接口数据,  返回数据. 进行数据处理 现在两部分比较重要:1 自动获取数据  ,  2处理excel的过程. 明白接口的过程.传入参数   htt ...

  10. DB2 设置最大连接数

    db2 connect to dbname user username using passwd db2 update db cfg using MAXAPPLS number 查看最大连接数 查看D ...