Java:浅克隆(shallow clone)与深克隆(deep clone)
Summary
浅克隆与深克隆对于JavaSE来说,是个难度系数比较低的概念,但不应该轻视它。
假设一个场景:对于某个list,代码里并没有任何对其的直接操作,但里面的元素的属性却被改变了,这可能就涉及到这个概念。
Description
浅克隆指仅copy对象位于栈内存中的引用(reference)。copy后,新旧两个引用指向同一个堆内存对象(即同一内存区域),但是堆内存中实际的对象copy前后均只有一个。使用"==" operator比较二者的地址会返回true。(不同引用,同一对象)
深克隆指则会copy一个新的对象并返回相应引用,即开辟了新的堆内存空间,因此使用“==” operator来比较两者的地址时会返回false。(不同引用,不同对象)
浅克隆(shallow clone)
- clone对象是实例对象时,使用“=”操作符进行浅克隆。
- 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中并没有显式定义深克隆,或者说并没有直接提供工具类来进行。要让你的自定义类支持深克隆,必须具备两个条件:
- implements Cloneable interface.
- 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
操作说明:
- 创建一个ArrayList对象list0
- list0中加入一个对象t
- 克隆list0对象为list1
- 再修改list0中元素(即t)的属性
结果说明:
- ArrayList实现了Cloneable接口,arraylist.clone()为深克隆,故list0与list1分别指向不同内存区域。
- ArrayList对象的clone()对于内部数组的元素仅为浅克隆,故list0中的元素(t)与list1中的元素为同一个,对list0元素的修改将影响到list1的元素。
Java:浅克隆(shallow clone)与深克隆(deep clone)的更多相关文章
- java 浅克隆(浅复制)和深克隆(深复制)
http://www.voidcn.com/blog/u011380813/article/p-6161450.html https://gold.xitu.io/entry/570d89651ea4 ...
- Deep Clone 常用方式总结
Deep Clone Example 总结 Deep Clone 一般有如下几种实现方式: 纯手工每个类实现赋值 (ps: 不做介绍,一般都不想这么玩) 序列化和反序列化 纯反射 emit 或 Exp ...
- 深拷贝(deep clone)与浅拷贝(shallow clone)
深拷贝(deep clone)与浅拷贝(shallow clone) 浅复制(浅克隆):被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之,浅复制仅仅复 ...
- java 浅克隆 深克隆
对象的克隆是java的一项高级技术,他可以根据给定的对象,获得与其完全相同的另一个对象. 1.浅克隆主要是复制对象的值 2.深克隆:当类存在聚合关系的时候,克隆就必须考虑聚合对象的克隆,可以复制引用类 ...
- java浅克隆和深克隆,序列化和反序列化实现深克隆(封装序列化和反序列化操作)
本篇博客内容: 一.浅克隆(ShallowClone)和深克隆(DeepClone) 二.序列化和反序列化实现深克隆 三.封装序列化和反序列化操作 ObjectOutputStream + 内存流By ...
- Ruby中如何复制对象 (deep clone)(转载)
Ruby中如何复制对象 (deep clone) 用Ruby复制一个对象(object)也许没有你想像的那么容易. 今天我google了半天, 做个总结吧. 先从最简单的开始, b = a 是复制吗? ...
- JavaScript 中的对象深度复制(Object Deep Clone)
JavaScript中并没有直接提供对象复制(Object Clone)的方法. JavaScript中的赋值,其实并不是复制对象,而是类似`c/c++`中的引用(或指针),因此下面的代码中改变对象b ...
- java中的Object类和其clone()
1.Object是所有类的父类,任何类都默认继承Object,即直接或间接的继承java.lang.Object类.由于所有的类都继承在Object类,因此省略了extends Object关键字. ...
- 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 ...
随机推荐
- poj 1050 To the Max 最大子矩阵和 经典dp
To the Max Description Given a two-dimensional array of positive and negative integers, a sub-rect ...
- RestTemplate请求https忽略证书认证
RestTemplate是Spring提供的用于访问Rest服务的客户端,提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率.RestTemplate 默认使用J2SE提供的方式( ...
- String类自带的字符串处理原生方法
一.取出指定索引的字符 —— 使用charAt()方法 二.字符串与字符数组的转换 三.字符串转大写.先转换成数组,然后再改变ASCII码 四.给定一个字符串,要求判断其是否由数字组成 五.字符串与字 ...
- apollo stomp client 代码示例
0.环境准备 0.1.linux 0.2.java 0.3.下载apollo二进制包,解压 0.4.创建broker,名字为 userlog {APOLLO_HOME}/bin/apollo crea ...
- c语言memset源码
c语言memset源码 一.用法 void *memset(void *s, int ch, size_t n);作用:将s所指向的某一块内存中的每个字节的内容全部设置为ch指定的ASCII值, 块的 ...
- 《Think in Java》(十四)类型信息
简介 RTTI,RunTime Type Information,运行时类型信息.Java 在运行时识别对象和类的信息主要有两种方式:一种是"传统的"RTTI,它假定我们在编译时已 ...
- 这真是奇葩的js题目
url:http://javascript-puzzlers.herokuapp.com/ 有兴趣的可以一看,算是比较偏门自我感觉
- android面试准备一之Activity相关
1.Activity生命周期 1.1 Activity的4种状态 running/paused/stopped/killed running:当前Activity正处于运行状态,指的是当前Ac ...
- 关闭多个screen
由于开了很多个screen同时工作,关闭是一个一个比较麻烦,写个命令在这以便日后想不起来时可以用到. 1.先看看有多少个screen screen -ls |awk '/Socket/'|awk ...
- dump相关
命令:jmap -dump:format=b,file=/tmp/dump.hprof pid jstack -l 30087 >> text.txt