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. poj 1050 To the Max 最大子矩阵和 经典dp

    To the Max   Description Given a two-dimensional array of positive and negative integers, a sub-rect ...

  2. RestTemplate请求https忽略证书认证

    RestTemplate是Spring提供的用于访问Rest服务的客户端,提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率.RestTemplate 默认使用J2SE提供的方式( ...

  3. String类自带的字符串处理原生方法

    一.取出指定索引的字符 —— 使用charAt()方法 二.字符串与字符数组的转换 三.字符串转大写.先转换成数组,然后再改变ASCII码 四.给定一个字符串,要求判断其是否由数字组成 五.字符串与字 ...

  4. apollo stomp client 代码示例

    0.环境准备 0.1.linux 0.2.java 0.3.下载apollo二进制包,解压 0.4.创建broker,名字为 userlog {APOLLO_HOME}/bin/apollo crea ...

  5. c语言memset源码

    c语言memset源码 一.用法 void *memset(void *s, int ch, size_t n);作用:将s所指向的某一块内存中的每个字节的内容全部设置为ch指定的ASCII值, 块的 ...

  6. 《Think in Java》(十四)类型信息

    简介 RTTI,RunTime Type Information,运行时类型信息.Java 在运行时识别对象和类的信息主要有两种方式:一种是"传统的"RTTI,它假定我们在编译时已 ...

  7. 这真是奇葩的js题目

    url:http://javascript-puzzlers.herokuapp.com/ 有兴趣的可以一看,算是比较偏门自我感觉

  8. android面试准备一之Activity相关

    1.Activity生命周期 1.1 Activity的4种状态   running/paused/stopped/killed   running:当前Activity正处于运行状态,指的是当前Ac ...

  9. 关闭多个screen

    由于开了很多个screen同时工作,关闭是一个一个比较麻烦,写个命令在这以便日后想不起来时可以用到. 1.先看看有多少个screen    screen -ls |awk '/Socket/'|awk ...

  10. dump相关

    命令:jmap -dump:format=b,file=/tmp/dump.hprof pid jstack -l 30087 >> text.txt