Java中的深克隆和浅克隆

为什么要克隆

首先思考一个问题, 为什么需要克隆对象? 直接new一个对象不行吗?

克隆的对象可能包含一些已经修改过的属性, 而new出来的对象的属性都还是初始化时候的值, 所以当需要一个新的对象来保存当前对象的"状态"时就要靠克隆了.

当然, 把对象的属性一个一个的赋值给新new的对象也是可以的, 但是这样一来麻烦不说, 二来, 我们通过源码查看 Object的clone方法是一个native方法(native方法是非Java语言实现的代码, 供Java程序调用, 要想访问比较底层的与操作系统相关的就没办法了, 只能由靠近操作系统的语言来实现), 就是快啊, 实在更底层实现的.

我们常见的 Object a = new Object(); Object b; b = a; 这种形式的代码复制的是引用, 即对象在内存中的地址, a和b指向了同一个对象. 而通过clone方法赋值的对象跟原来的对象是同时独立存在的.

概念

浅克隆:

被克隆的对象里的所有变量值都与原来的对象相同, 而所有对其他对象的引用仍然指向原来的对象. 简单说, 浅克隆仅克隆当前对象, 而不克隆当前对象所引用的对象.

深克隆:

被克隆的对象里的所有变量值都与原来的对象相同, 那些引用其他对象的变量将指向被复制过的新对象, 而不再是原来被引用的对象. 简单说, 深克隆不仅克隆了当前对象, 还把当前对象所引用的对象都复制了一遍.

Object中的clone

Object类中的clone()方法属于浅克隆. 它的工作原理如下: 在内存中先开辟一块和原始对象相同的空间, 然后复制原始对象的内容. 对于基本数据类型, 这样操作当然没问题, 但对于引用类型, 由于保存的仅仅是对象的引用, 克隆过去的引用所指向的是同一个对象.

Java中实现浅克隆

java中实现clone要实现 Cloneable 接口, 该接口十分简单, 源码如下:

仅仅起到一个标识的作用.

下面是一个实现浅克隆的例子:

可以看到, 对象确实不是原来的对象了, 但是其中的引用对象却还是原来的对象.

浅克隆对于引用对象仅拷贝引用.

如果一个对象只包含原始数据或者不可变对象域(如: String), 推荐使用浅克隆.

Java中实现深克隆

将类中的所有引用类型都进行clone, 并重写对象clone()方法, 对所有引用类型进行clone.

代码如下:

将所有引用类型都进行clone, 实现了深克隆.

Java序列化克隆

如果引用类型中海包括引用类型, 要实现多层克隆会很麻烦, 这使用可以使用序列化和反序列化的方式实现对象的深克隆.

把对象写到字节流中的过程是序列化的过程, 而把对象从字节流中读出来的过程是反序列化的过程. 由于Java序列化的过程中, 写在流中的是对象的一个拷贝, 而原对象仍然在JVM中, 所以可以利用这个原理来实现对对象的深克隆.

上面代码使用序列化实现如下:

可以将序列化克隆封装为一个方法, 如下所示:

通过该工具类即可进行深度克隆. 要是用该方法, 对象、对象的所有引用类型、引用类型中的引用类型都要实现 Serializable 接口.



当然, 对象中的final对象是不能进行clone的, 因为final的限制.

如果用线程安全的类实现Cloneable, 要保证它的clone方法做好同步工作, 默认的Object.clone方法是没有同步的.

原文地址:https://www.cnblogs.com/hujingnb/p/10181582.html

时间: 2024-08-25 21:55:58

Java中的深克隆和浅克隆的相关文章

Java中的深克隆和浅克隆——Cloneable接口

一.没有使用克隆带来的问题 public class CloneTest { static Student s = new Student("aaa", 20); // 直接赋值带来的问题 public static void noclone() { // 传的是引用的副本,改变了noCloneStudent也改变了s Student noCloneStudent = new Student(); noCloneStudent = s; noCloneStudent.setName(&

JAVA深克隆与浅克隆1

复制就是得到一个副本 克隆就是复制一个对象的复本.但一个对象中可能有基本数据类型,如:int,long,float    等,也同时含有非基本数据类型如(数组,集合等)被克隆得到的对象基本类型的值修改了,原对象的值不会改变.这种适合shadow clone(浅克隆). 但如果你要改变一个非基本类型的值时,原对象的值却改变了.比如一个数组,内存中只copy他的地址,而这个地址指向的值并没有copy,当clone时,两个地址指向了一个值,这样一旦这个值改变了,原来的值当然也变了,因为他们共用一个值.

Java深拷贝和浅拷贝(深克隆和浅克隆)

Java中创建对象有两种方式: 通过new操作符创建一个对象 通过clone方法来复制一个对象 使用反序列化来创建一个对象 通过使用Class类的newInstance方法来创建一个对象 使用Constructor类的newInstance方法来创建一个对象 第一种方法,通过new操作符来创建一个对象,分配内存,调用构造函数来填充各个域,这是我们最熟悉的:第二种clone也是分配内存,分配的内存和被clone对象相同,然后再使用原对象中对应的各个域,填充新对象的域, 填充完成之后,clone方法

Java克隆--深克隆与浅克隆的区别

克隆,就是复制一个对象的副本,而克隆又分浅克隆和深克隆.浅克隆是指克隆得到的对象基本类型的值改变了,而源对象的值不会变.但如果被克隆对象引用类型的值改变了,那么源对象的值同样会改变,因为引用类型在栈内存中存放的是一个引用地址,被克隆对象后也和源对象的引用地址一样,都是指向同样的内存空间的值.所以在克隆时,任何一个对象的值的改变都会令另外的值改变,所以这种情况下要用深克隆. 要注意的是要克隆的对象的泪必须继承cloneable接口.浅克隆的特点是只克隆该对象本体,它的优缺点就是一改皆改:深克隆的特

java中关于对象的复制

java中的对象复制有两种方法,可以简略的称为浅克隆和深克隆 浅克隆:调用object的clone接口实现克隆,之所以称为浅克隆,是因为在复制的过程中将对象的成员变量中的基本数据类型直接复制,但是对于引用数据类型只是将复制对象成员变量的引用传递过去,并没有对于新对象生成新的成员变量,需要注意的地方,object的clone()方法的访问修饰符是protect的,所以,需要在对象中重写clone方法,将其访问修饰符修改为public方法即可 深克隆:将当前对象以及对象的成员变量完整的复制,生成一个

Java中的深拷贝和浅拷贝

1.浅拷贝与深拷贝概念 (1)浅拷贝(浅克隆) 浅拷贝又叫浅复制,将对象中的所有字段复制到新的对象(副本)中.其中,值类型字段(java中8中原始类型)的值被复制到副本中后,在副本中的修改不会影响到源对象对应的值.而引用类型的字段被复制到副本中的还是引用类型的引用,而不是引用的对象,在副本中对引用类型的字段值做修改会影响到源对象本身. 浅拷贝简单归纳就是只复制一个对象,对象内部存在指向其他对象,数组或引用则不复制. (2)深拷贝(深克隆) 将对象中的所有字段复制到新的对象中.不过,无论是对象的值

Java中的clone()----深复制,浅复制

这篇文章主要介绍了Java中对象的深复制(深克隆)和浅复制(浅克隆) ,需要的朋友可以参考下 1.浅复制与深复制概念 ⑴浅复制(浅克隆) 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象. ⑵深复制(深克隆) 被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量.那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象.换言之,深复制把要复制的对象所引用

Java中如何克隆集合——ArrayList和HashSet深拷贝

编程人员经常误用各个集合类提供的拷贝构造函数作为克隆List,Set,ArrayList,HashSet或者其他集合实现的方法.需要记住的是,Java集合的拷贝构造函数只提供浅拷贝而不是深拷贝,这意味着存储在原始List和克隆List中的对象是相同的,指向Java堆内存中相同的位置.增加了这个误解的原因之一是对于不可变对象集合的浅克隆.由于不可变性,即使两个集合指向相同的对象是可以的.字符串池包含的字符串就是这种情况,更改一个不会影响到另一个.使用ArrayList的拷贝构造函数创建雇员List

深克隆和浅克隆

深克隆和浅克隆 标签(空格分隔): 常用函数 浅克隆 浅克隆: 被复制对象的所有基本变量都含有和原来变量完全相同的值, 而其他所有的引用对象任然指向原来的对象. 换言之, 浅克隆仅仅复制锁考虑的对象, 而不复制它所引用的对象. 克隆的深度仅仅到栈内存中. 深克隆 深克隆: 和浅克隆不一样的点在于其重写了clone函数. 在克隆本身对象的时候, 也对其中的引用类型的属性进行克隆. 看下面的代码, 为什么String就这么吊, 好像直接就是深克隆呢? 不同点在于, 在浅克隆的时候 gg属性是 栈内存