转载:http://atjava.iteye.com/blog/1722501

首先我们看看浅拷贝和深拷贝的定义

浅拷贝:只复制一个对象,对象内部存在的指向其他对象数组或者引用则不复制 
深拷贝:对象,对象内部的引用均复制 
  为了更好的理解它们的区别我们假设有一个对象A,它包含有2对象,对象A1和对象A2 
  对象A进行浅拷贝后,得到对象B但是对象A1和A2并没有被拷贝 
  对象A进行深拷贝,得到对象B的同时A1和A2连同它们的引用也被拷贝 
  在理解了深拷贝和浅拷贝后,我们来看看Java的深拷贝和浅拷贝实现.

Object 类的 clone方法执行特定的克隆操作。 
首先,如果此对象的类不能实现接口 Cloneable,则会抛出 CloneNotSupportedException。(注意:所有的数组都被视为实现接口 Cloneable) 
此方法会创建此对象的类的一个新实例,并像通过分配,严格使用此对象相应字段的内容初始化该对象的所有字段;这些字段的内容没有被自我克隆。所以,此方法执行的是该对象的“浅表复制”,而不“深层复制”操作。 
Object 类本身不实现接口 Cloneable,所以在类为 Object的对象上调用 clone 方法将会导致在运行时抛出异常。

下面从三个复制的实例代码来看它们之间的区别,我们需建立Person类:

  1. public class Person{
  2. private String name;
  3. private int age;
  4. public Person(String name, int age) {
  5. this.name = name;
  6. this.age = age;
  7. }
  8. public void setAge(int age) {
  9. this.age = age;
  10. }
  11. public void setName(String name) {
  12. this.name = name;
  13. }
  14. public void display() {
  15. System.out.println("Name:" + name + "/tAge:" + age);
  16. }
  17. }

一、普通复制 
即我们最容易想到的将一个对象赋值给另外一个对象。

  1. public static void main(String[] args) {
  2. Person p1=new Person("jack",20);
  3. Person p2=p1;
  4. p1.setAge(49);//简单复制
  5. p2.display();
  6. p1.display();
  7. System.out.println(p1);
  8. System.out.println(p2);
  9. }

结果:        Name:jack    Age:49 
               Name:jack   Age:49 
               net.pcedu.clone.Person@c17164 
               net.pcedu.clone.Person@c17164 
说明p1和p2对象的是同一个引用,所以再改属性2个都是改变的。

二、浅拷贝 
浅拷贝必需对Book类实现Cloneable接口的clone方法

  1. public class Book implements Cloneable{
  2. String bookName;
  3. double price;
  4. Person author;
  5. public Book(String bn,double price,Person author){
  6. bookName = bn;
  7. this.price = price;
  8. this.author = author;
  9. }
  10. public Object clone(){
  11. Book b = null;
  12. try{
  13. b = (Book)super.clone();
  14. }catch(CloneNotSupportedExceptione){
  15. e.printStackTrace();
  16. }
  17. return b;
  18. }
  19. public void display(){
  20. System.out.print(bookName + "/t" +price + "/t") ;
  21. author.display();
  22. }
  23. }
  24. publicstatic void main(Stringargs[]){
  25. Book b1 = new Book("Java编程",30.50,new Person("张三",34));
  26. Book b2 = (Book)b1.clone();
  27. b2.price = 44.0;
  28. b2.author.setAge(45);
  29. b2.author.setName("李四");
  30. b2.bookName = "Java开发";
  31. b1.display();
  32. b2.display();
  33. }

结果: 
Java编程  30.5   Name:李四 Age:45 
Java开发  44.0   Name:李四 Age:45 
说明b1和b2是不同的对象,但是b1.author和b2.author指向同一对象,。

问题如下: 发现在改变b2的author对象属性时b1的author对象的属性也改变了,说明在浅拷贝中的author这个对象没有被完全拷贝,而是使用同一引用,这样就要使用深拷贝了。

三、深拷贝 
为了解决如上问题,我们需要用到深拷贝,其实很简单在拷贝book对象的时候加入如下语句

  1. b.author =(Person)author.clone(); //将Person对象进行拷贝,Person对象需进行了拷贝

在运行上面的main方法,结果如下: 
  Java编程30.5   Name:张三 Age:34 
Java开发44.0   Name:李四 Age:45 
说明b1和b2是不同的对象,b1.author和b2.author指向不同对象,。(含引用对象属性的拷贝)。

java.lang.t的clone()方法默认是返回一个前拷贝对象。因此如果要用clone()方法实现一个深拷贝,我们必须对每个对象的clone()方法进行特别实现。当对象层次复杂的时候,这样做不但困难而且浪费时间和容易出现错误,特别有时候你不但需要深拷贝同时你也对这个对象进行浅拷贝的时候,你会发现写这个clone()方法真不是一个好的解决方案。

那么除了clone()方法,我们还可以怎么实现呢?答案是序列化 
序列化的对象要实现Serializable接口才能实现序列化,同时,对象的成员对象也要实现序列化.

  1. A a=new A();
  2. //写对象,序列化
  3. ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
  4. ObjectOutputStream out= new ObjectOutputStream(byteOut);
  5. out.writeObject(a);
  6. //读对象,反序列化
  7. ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
  8. A b=(A)in.readObject();

序列化经常用于文件传递的读取。尤其是在缓存中用得比较多,通过序列化可以将对象缓存在硬盘中。这在登录系统缓存用户权限和角色等信息最常见。而用对克隆对象,也不失为一种很好的方法。

java.lang.Object类的clone方法是一个protected方法,在子类需要重写此方法并声明为public类型,而且还需实现Cloneable接口才能提供对象复制的能力,clone()是一个native方法,native方法的效率一般来说都是远高于java中的非native方法,对性能比较关心的话首先考虑这种方式,另一种方式——通过java的反射机制复制对象,这种方式效率可能会比clone()低,而且不支持深度复制以及复制集合类型,但通用性会提高很多,下边是进行复制的代码:

  1. private <T> T getBean(T TargetBean, T SourceBean) {
  2. if (TargetBean== null) return null;
  3. Field[] tFields = TargetBean.getClass().getDeclaredFields();
  4. Field[] sFields = SourceBean.getClass().getDeclaredFields();
  5. try {
  6. for (Field field : tFields ) {
  7. String fieldName = field.getName();
  8. if (fieldName.equals("serialVersionUID")) continue;
  9. if (field.getType() == Map.class) continue;
  10. if (field.getType() == Set.class) continue;
  11. if (field.getType() == List.class) continue;
  12. for (Field sField : sFields) {
  13. if(!sField .getName().equals(fieldName)){
  14. continue;
  15. }
  16. Class type = field.getType();
  17. String setName = getSetMethodName(fieldName);
  18. Method tMethod = TargetBean.getClass().getMethod(setName, new Class[]{type});
  19. String getName = getGetMethodName(fieldName);
  20. Method sMethod = SourceBean.getClass().getMethod(getName, null);
  21. Object setterValue = voMethod.invoke(SourceBean, null);
  22. tMethod.invoke(TargetBean, new Object[]{setterValue});
  23. }
  24. }
  25. } catch (Exception e) {
  26. throw new Exception("设置参数信息发生异常", e);
  27. }
  28. return TargetBean;
  29. }

该方法接收两个参数,一个是复制的源对象——要复制的对象,一个是复制的目标对象——对象副本,当然这个方法也可以在两个不同对象间使用,这时候只要目标对象和对象具有一个或多个相同类型及名称的属性,那么就会把源对象的属性值赋给目标对象的属性。

java深浅拷贝的更多相关文章

  1. java提高(15)---java深浅拷贝

    #java深浅拷贝 一.前言 为什么会有深浅拷贝这个概念? 我觉得主要跟JVM内存分配有关,对于基本数据类型,只存在栈内存,所以它的拷贝不存在深浅拷贝这个概念.而对于对象而言,一个对象的创建会在内存中 ...

  2. Java 深浅拷贝

    2016-07-02 1深拷贝:不仅拷贝对象,而且对象所引用地址的内容一块拷贝.改变一个对象的某个属性,并不影响另一个对象所引用的内容. 2浅拷贝:仅拷贝对象本身,并不对所引用(所指的)内容进行拷贝, ...

  3. 一文搞懂Java引用拷贝、浅拷贝、深拷贝

    微信搜一搜 「bigsai」 专注于Java和数据结构与算法的铁铁 文章收录在github/bigsai-algorithm 在开发.刷题.面试中,我们可能会遇到将一个对象的属性赋值到另一个对象的情况 ...

  4. 一文搞懂Java引用拷贝、深拷贝、浅拷贝

    刷题.面试中,我们可能会遇到将一个对象的属性赋值到另一个对象的情况,这种情况就叫做拷贝.拷贝与Java内存结构息息相关,搞懂Java深浅拷贝是很必要的! 在对象的拷贝中,很多初学者可能搞不清到底是拷贝 ...

  5. java Clone之深浅拷贝

    要点: 1.浅度拷贝可以不实现Cloneable接口(自动使用Object.clone)或者不重写Cloneable的clone方法. 2.要被深度拷贝的类必须实现Cloneable接口并重写clon ...

  6. 关于Java中的HashMap的深浅拷贝的测试与几点思考

    0.前言 工作忙起来后,许久不看算法,竟然DFA敏感词算法都要看好一阵才能理解...真是和三阶魔方还原手法一样,田园将芜,非常可惜啊. 在DFA算法中,第一步是需要理解它的数据结构,在此基础上,涉及到 ...

  7. 关于Java的Object.clone()方法与对象的深浅拷贝

    文章同步更新在个人博客:关于Java的Object.clone()方法与对象的深浅拷贝 引言 在某些场景中,我们需要获取到一个对象的拷贝用于某些处理.这时候就可以用到Java中的Object.clon ...

  8. 什么是java的深浅拷贝?

    什么是java的深浅拷贝? 浅拷贝 就是很肤浅的拷贝,只拷贝了别人的地址.没有拷贝地址里面的值.地址里面的值改变后,就都改变了. 深拷贝 就是很深入的拷贝,深入到核心的拷贝,拷贝了别人地址里面的值,别 ...

  9. 学习--->更新集合/内存/深浅拷贝

     一.计算机基础 1..软件(应用程序) 2.解释器/编译器 - 解释型语言:将代码每一行传递给计算机一行,常用编程语言python,PHP,Ruby. - 编译型语言:将代码完全执行完后会形成一个文 ...

随机推荐

  1. MQ内存消耗与积压分析

    [root@iZ23nn1p4mjZ logs]# rabbitmqctl status Status of node rabbit@iZ23nn1p4mjZ ... [{pid,15425}, {r ...

  2. 算法之路 level 01 problem set

    2992.357000 1000 A+B Problem1214.840000 1002 487-32791070.603000 1004 Financial Management880.192000 ...

  3. C++类的静态成员变量初始化 Win32 API 定时器使用

    1.类的静态成员变量 .h 类声明入下 class A { public: static int x; }; .cpp文件 这样初始化. ; 2.定时器使用 1.SetTimer(HWND,UINT, ...

  4. FJNUOJ the greed of Yehan(最长路 + 权值乘积转化)题解

    Description During the trip, Yehan and Linlin pass a cave, and there is a board at the door, which s ...

  5. Win7系统中如何查看当前文件被哪一个程序占用了

    https://superuser.com/questions/117902/find-out-which-process-is-locking-a-file-or-folder-in-windows ...

  6. ACM-ICPC 2018 南京赛区网络预赛 L. Magical Girl Haze 最短路+分层图

    类似题解 There are NN cities in the country, and MM directional roads from uu to v(1\le u, v\le n)v(1≤u, ...

  7. CodeForces 1029E div3

    题目链接 第一道场上自己做出来的E题...虽然是div3,而且是原题... 当时做完ABC,D题没有思路就去怼E了,然后发现貌似原题? 事实上就是原题... 给个原题链接... [HNOI2003]消 ...

  8. 初始 DQN 程序 所遇到的问题

    初始 DQN 程序 所遇到的问题 最近在看 DQN,但是想试试别人放出来的 code,但是发现,额,各种问题,在此记录,以备不时之需! 问题1. wangxiao@GTX980:~/Documents ...

  9. 【TCP/IP详解 卷一:协议】第十章 动态选路协议

    更为详细的RIP博客解析: RIP理论 距离向量算法的简介: RIP协议V-D算法的介绍 10.1 引言 静态选路修改路由表的三种方法 (1)主机设置时,默认的路由表项 (2)ICMP重定向报文(默认 ...

  10. 机器学习 MLIA学习笔记(一)

    监督学习(supervised learning):叫监督学习的原因是因为我们告诉了算法,我们想要预测什么.所谓监督,其实就是我们的意愿是否能直接作用于预测结果.典型代表:分类(classificat ...