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 ...
随机推荐
- apache解压版安装服务
解压版也就是绿色版 到apache/bin目录 然后运行下面命令 httpd.exe -k install -n "Apache24" 如果要卸载服务的话,就是下面这个命令 htt ...
- nwafu - java实习 JDBC练习 - 学生信息系统界面
学生信息系统界面的实现 - JDBC writer:pprp 登录界面的实现: 分为两个部分: 1.LoginFrame.java : 用windowbuilder进行快速搭建界面,构建好登录的界面, ...
- wireshark抓包分析
TCP协议首部: 分析第一个包: 源地址:我自己电脑的IP,就不放上来了 Destination: 222.199.191.33 目的地址 TCP:表明是个TCP协议 Length:66 表明包的长度 ...
- Python类变量,实例变量,类方法,实例方法,静态方法的分析
Python作为动态语言,跟静态语言如c/c++有很大区别,其中的一个重要的特性就是Python的变量无需声明直接可用.同样,类的成员变量无需声明,直接可用.目的是为了动态语言跟灵活,在思路想到的时候 ...
- cygwin下安装软件
cygwin下安装软件cygwin工具安装新的软件和常见的命令windows8.1下安装Cygwin并通过apt-cyg安装软件包Cygwin利用apt-cyg安装gcc.g++.make和gdb 首 ...
- Win7 64位安装VS2013无法连接远程数据库
win7 64位安装vs2013后连接远程数据库出现下面的问题:A first chance exception of type 'System.AccessViolationException' o ...
- sql数据类型转换函数
1.CAST()CAST (<expression> AS <data_ type>[ length ]) 2.CONVERT()CONVERT (<data_ type ...
- UML中的组合、聚合、关联、继承、实现、依赖
转自:http://justsee.iteye.com/blog/808799 UML定义的关系主要有六种:依赖.类属.关联.实现.聚合和组合. 继承 指的是一个类(称为子类.子接口)继承另外的一个类 ...
- Docker 学习记录笔记(一)
Docker 一些简单的命令列表docker build -t friendlyhello . # Create image using this directory's Dockerfiledock ...
- CentOS 7添加应用快捷方式到桌面
以eclipse为例,编辑下面文件,复制到桌面即可. vi client.desktop [Desktop Entry]Encoding=UTF-8Name=eclipseExec=/home/clo ...