1、概念

java里的clone分为: 
A:浅复制(浅克隆): 浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。 
b:深复制(深克隆):深复制把要复制的对象所引用的对象都复制了一遍。 
Java中对象的克隆,为了获取对象的一份拷贝,我们可以利用Object类的clone()方法。必须要遵循下面三点 
1.在派生类中覆盖基类的clone()方法,并声明为public【Object类中的clone()方法为protected的】。 
2.在派生类的clone()方法中,调用super.clone()。 
3.在派生类中实现Cloneable接口。

注明:Object类里的clone方法是浅复制(浅克隆)

2.Java的clone()方法

⑴clone方法将对象复制了一份并返回给调用者。一般而言,clone()方法满足: 
①对任何的对象x,都有x.clone() !=x//克隆对象与原对象不是同一个对象 
②对任何的对象x,都有x.clone().getClass()= =x.getClass()//克隆对象与原对象的类型一样 
③如果对象x的equals()方法定义恰当,那么x.clone().equals(x)应该成立。

⑵Java中对象的克隆

①为了获取对象的一份拷贝,我们可以利用Object类的clone()方法。 
②在派生类中覆盖基类的clone()方法,并声明为public。 
③在派生类的clone()方法中,调用super.clone()。 
④在派生类中实现Cloneable接口。

请看下面代码:

  1. public class Student implements Cloneable
  2. {
  3. String name;
  4. int age;
  5. Student(String name,int age)
  6. {
  7. this.name=name;
  8. this.age=age;
  9. }
  10. public Object clone()
  11. {
  12. Object o=null;
  13. try
  14. {
  15. o=(Student)super.clone();//Object 中的clone()识别出你要复制的是哪一个对象。
  16. }
  17. catch(CloneNotSupportedException e)
  18. {
  19. System.out.println(e.toString());
  20. }
  21. return o;
  22. }
  23.  
  24. public static void main(String[] args)
  25. {
  26. Student s1=new Student("zhangsan",18);
  27. Student s2=(Student)s1.clone();
  28. s2.name="lisi";
  29. s2.age=20;
  30. //修改学生2后,不影响学生1的值。
  31. System.out.println("name="+s1.name+","+"age="+s1.age);
  32. System.out.println("name="+s2.name+","+"age="+s2.age);
  33. }
  34. }

  说明: 
①为什么我们在派生类中覆盖Object的clone()方法时,一定要调用super.clone()呢?在运行时刻,Object中的clone()识别出你要复制的是哪一个对象,然后为此对象分配空间,并进行对象的复制,将原始对象的内容一一复制到新对象的存储空间中。 
②继承自java.lang.Object类的clone()方法是浅复制。以下代码可以证明之。

  1. class Professor implements Cloneable
  2. {
  3. String name;
  4. int age;
  5. Professor(String name,int age)
  6. {
  7. this.name=name;
  8. this.age=age;
  9. }
  10. public Object clone()
  11. {
  12. Object o=null;
  13. try
  14. {
  15. o=super.clone();
  16. }
  17. catch(CloneNotSupportedException e)
  18. {
  19. System.out.println(e.toString());
  20. }
  21. return o;
  22. }
  23. }
  24. public class Student implements Cloneable
  25. {
  26. String name;
  27. int age;
  28. Professor p;
  29. Student(String name,int age,Professor p)
  30. {
  31. this.name=name;
  32. this.age=age;
  33. this.p=p;
  34. }
  35. public Object clone()
  36. {
  37. Student o=null;
  38. try
  39. {
  40. o=(Student)super.clone();
  41. }
  42. catch(CloneNotSupportedException e)
  43. {
  44. System.out.println(e.toString());
  45. }
  46. //对引用的对象也进行复制
  47. o.p=(Professor)p.clone();
  48. return o;
  49. }
  50. public static void main(String[] args)
  51. {
  52. Professor p=new Professor("wangwu",50);
  53. Student s1=new Student("zhangsan",18,p);
  54. Student s2=(Student)s1.clone();
  55. s2.p.name="lisi";
  56. s2.p.age=30;
  57. //学生1的教授不 改变。
  58. System.out.println("name="+s1.p.name+","+"age="+s1.p.age);
  59. System.out.println("name="+s2.p.name+","+"age="+s2.p.age);
  60. }
  61. }

那应该如何实现深层次的克隆,即修改s2的教授不会影响s1的教授?代码改进如下。 
改进使学生1的Professor不改变(深层次的克隆)

  1. public class Student implements Cloneable
  2. {
  3. String name;
  4. int age;
  5. Professor p;
  6. Student(String name,int age,Professor p)
  7. {
  8. this.name=name;
  9. this.age=age;
  10. this.p=p;
  11. }
  12. public Object clone()
  13. {
  14. Student o=null;
  15. try
  16. {
  17. o=(Student)super.clone();
  18. }
  19. catch(CloneNotSupportedException e)
  20. {
  21. System.out.println(e.toString());
  22. }
  23. //对引用的对象也进行复制
  24. o.p=(Professor)p.clone();
  25. return o;
  26. }
  27. public static void main(String[] args)
  28. {
  29. Professor p=new Professor("wangwu",50);
  30. Student s1=new Student("zhangsan",18,p);
  31. Student s2=(Student)s1.clone();
  32. s2.p.name="lisi";
  33. s2.p.age=30;
  34. //学生1的教授不 改变。
  35. System.out.println("name="+s1.p.name+","+"age="+s1.p.age);
  36. System.out.println("name="+s2.p.name+","+"age="+s2.p.age);
  37. }
  38. }

  3.利用串行化来做深复制(主要是为了避免重写比较复杂对象的深复制的clone()方法,也可以程序实现断点续传等等功能) 
    把对象写到流里的过程是串行化(Serilization)过程,但是在Java程序师圈子里又非常形象地称为“冷冻”或者“腌咸菜(picking)”过程;而把对象从流中读出来的并行化(Deserialization)过程则叫做 “解冻”或者“回鲜(depicking)”过程。 
    应当指出的是,写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面,因此“腌成咸菜”的只是对象的一个拷贝,Java咸菜还可以回鲜。 
    在Java语言里深复制一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里(腌成咸菜),再从流里读出来(把咸菜回鲜),便可以重建对象。 
如下为深复制源代码。

  1. public Object deepClone()
  2. {
  3. //将对象写到流里
  4. ByteArrayOutoutStream bo=new ByteArrayOutputStream();
  5. ObjectOutputStream oo=new ObjectOutputStream(bo);
  6. oo.writeObject(this);
  7. //从流里读出来
  8. ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray());
  9. ObjectInputStream oi=new ObjectInputStream(bi);
  10. return(oi.readObject());
  11. }

这样做的前提是对象以及对象内部所有引用到的对象都是可串行化的,否则,就需要仔细考察那些不可串行化的对象或属性可否设成transient,从而将之排除在复制过程之外。上例代码改进如下。

  1. class Teacher implements Serializable {
  2. String name;
  3. int age;
  4. public void Teacher(String name,int age){
  5. this.name=name;
  6. this.age=age;
  7. }
  8. }
  9. public class Student implements Serializable{
  10. String name;//常量对象
  11. int age;
  12. Teacher t;//学生1和学生2的引用值都是一样的。
  13. public void Student(String name,int age,Teacher t){
  14. this.name=name;
  15. this.age=age;
  16. this.p=p;
  17. }
  18. public Object deepClone() throws IOException,
  19. OptionalDataException,ClassNotFoundException{//将对象写到流里
  20. ByteArrayOutoutStream bo=new ByteArrayOutputStream();
  21. ObjectOutputStream oo=new ObjectOutputStream(bo);
  22. oo.writeObject(this);//从流里读出来
  23. ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray());
  24. ObjectInputStream oi=new ObjectInputStream(bi);
  25. return(oi.readObject());
  26. }
  27. public static void main(String[] args){
  28. Teacher t=new Teacher("tangliang",30);
  29. Student s1=new Student("zhangsan",18,t);
  30. Student s2=(Student)s1.deepClone();
  31. s2.t.name="tony";
  32. s2.t.age=40;
  33. //学生1的老师不改变
  34. System.out.println("name="+s1.t.name+","+"age="+s1.t.age);
  35. }
  36. }

 参考:http://www.jb51.net/article/62909.html

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

  1. Java 深拷贝和浅拷贝 利用序列化实现深拷贝

    Java 深拷贝和浅拷贝 转自:http://www.cnblogs.com/mengdd/archive/2013/02/20/2917971.html 深拷贝(deep clone)与浅拷贝(sh ...

  2. java 深拷贝与浅拷贝机制详解

    概要: 在Java中,拷贝分为深拷贝和浅拷贝两种.java在公共超类Object中实现了一种叫做clone的方法,这种方法clone出来的新对象为浅拷贝,而通过自己定义的clone方法为深拷贝. (一 ...

  3. java深拷贝与浅拷贝

    1.调用Object类的clone方法必须实现Cloneable接口,clone属于浅拷贝. 2.可以通过java的反序列化机制进行深拷贝. 3.可以直接用apache提供的一些包进行深拷贝和浅拷贝, ...

  4. Java问题解读系列之IO相关---Java深拷贝和浅拷贝

    前几天和棒棒童鞋讨论Java(TA学的是C++)的时候,他提到一个浅拷贝和深拷贝的问题,当时的我一脸懵圈,感觉自己学Java居然不知道这个知识点,于是今天研究了一番Java中的浅拷贝和深拷贝,下面来做 ...

  5. java 深拷贝与浅拷贝

    yls 2019年11月07日 拷贝分为引用拷贝和对象拷贝 深拷贝和浅拷贝都属于对象拷贝 浅拷贝:通过Object默认的clone方法实现 实现Cloneable接口 public class She ...

  6. Java 深拷贝、浅拷贝及Cloneable接口

    Cloneable接口是一个空接口,仅用于标记对象,Cloneable接口里面是没有clone()方法,的clone()方法是Object类里面的方法!默认实现是一个Native方法 protecte ...

  7. Java深拷贝和浅拷贝的区别

    浅拷贝 被复制的对象的所有的变量都与原对象有相同的值,而所有的引用对象仍然指向原来的对象.换言之,浅拷贝 不复制引用对象. 1 class Experience { 2 private String ...

  8. Java 深拷贝,浅拷贝

    一直听说这两个词,确实不知道代表啥意思?也不知道究竟要用来做什么?什么时候用到他们. 下面是从一篇博文种得到的解释: 浅复制(浅克隆) :被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他 ...

  9. 001 Java 深拷贝、浅拷贝及Cloneable接口

    原本写过,后来在阅读的时候,感觉自己都不是太明白了,删除后参考人家的又重新写了一份. 一:开篇 1.复制一个变量 举例是int类型. 其他其中七种原始数据类型同样适用. 原始类型:boolean,ch ...

随机推荐

  1. HTML URL

    HTML 统一资源定位器(Uniform Resource Locators) URL 是一个网页地址. URL可以由字母组成,如"runoob.com",或互联网协议(IP)地址 ...

  2. C# INotifyPropertyChanged使用方法

    INotifyPropertyChanged 接口:向客户端发出某一属性值已更改的通知. NotifyPropertyChanged 接口用于向客户端(通常是执行绑定的客户端)发出某一属性值已更改的通 ...

  3. .md即markdown文件的基本常用编写语法(图文并茂)

    序言: 很久没有写博客了,感觉只要是不写博客,人就很变得很懒,学的知识点感觉还是记不住,渐渐地让我明白,看的越多,懂的越少(你这话不是有毛病吗?应该是看的越多,懂的越多才对),此话怎讲,当你在茫茫的前 ...

  4. Spring事务配置的五种方式和spring里面事务的传播属性和事务隔离级别

    转: http://blog.csdn.net/it_man/article/details/5074371 Spring事务配置的五种方式 前段时间对Spring的事务配置做了比较深入的研究,在此之 ...

  5. C# 数组、ArrayList、List、Dictionary的用法与区别

    前言 在工作中经常遇到C#数组.ArrayList.List.Dictionary存取数据,但是该选择哪种类型进行存储数据,对于初学者的我一直不知道该怎么取舍.于是抽空好好看了下他们的用法和比较,在这 ...

  6. shell 快速入门

    1: 脚本开始行 #!/bin/bash 这一行表明,不管用户选择的是那种交互式shell,该脚本需要使用bash shell来运行. 由于每种shell的语法大不相同,所以这句非常重要. 2:变量 ...

  7. 前端开发在IOS端遇到的一个诡异问题(Delegate 失效)

    一.前言 最近同事问到一个问题,一个前端页面在IOS端真机测试下出现一个比较诡异的问题,如果没有遇到过估计也是一筹莫展.今天特此记录一下,或许能帮到后面遇到这个问题的朋友少绕一些弯路.这是关于JQue ...

  8. linux文本处理常用指令总结

    引子 作为一个偏爱windows的程序员,以前做文本处理的时候总是喜欢在windows下用notepad++等图形化工具处理,比如有时需要把linux服务器上一个文件进行一次全局字符串替换这样简单的操 ...

  9. Java程序测试之线程的同步

    package tickect; class ticketnum implements Runnable { public int tickets = 100; String str = new St ...

  10. JavaScript中的this关键字的用法和注意点

    JavaScript中的this关键字的用法和注意点 一.this关键字的用法 this一般用于指向对象(绑定对象); 01.在普通函数调用中,其内部的this指向全局对象(window); func ...