第三节:浅拷贝和深拷贝

一、浅拷贝

  1、对于数据类型是基本数据类型的成员变量,浅拷贝会直接直接值传递,也就是将该属性值复制一份给新的对象;

  2、对于数据类型是引用数据的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值;

  3、前面的克隆羊就是浅拷贝,默认调用 clone() 方法来实现的;

  String拷贝的特殊性:

String 类型很特殊,它是不可变类型,即一旦初始化后,就不可以改变。因为他为引用型,而且他指向的值为常量,克隆出来的对象改变他的值,实际上是改变了克隆出来对象String类型成员的指向,不会影响被克隆对象的。


解释:如果原来对象的一个string变量进行初始化的时候,指向的是一个字符串常量,该字符串常量会被放到常量池中,该string类型的引用将会指向该常量。进行克隆后,得到一个新的对象,如果该对象的string变量重新赋值,那么只会有这个string 引用变量指向一个新的内存区域,对原来对象中的string变量不会有影响。

克隆相当于 1 个 String 内存空间有两个引用,当修改其中的一个值的时候,会新分配一块内存用来保存新的值,这个引用指向新的内存空间,原来的 String 因为还存在指向他的引用,所以不会被回收,这样,虽然是复制的引用,但是修改值的对象,并没有改变被复制对象的值。

二、深拷贝

  1、复制对象的所有基本数据类型的成员变量值;

  2、为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象。也就说,对象进行深拷贝要对整个对象进行拷贝

  3、深拷贝实现方式1:重写 clone 方法来实现深拷贝;

  4、深拷贝实现方式2:通过对象序列化实现深拷贝(推荐使用)

三、深拷贝代码实现:

  代码实现:

  1 public class DeepCloneableTarget implements Serializable, Cloneable {
  2 
  3 
  4     private static final long serialVersionUID = -8179039019334069484L;
  5 
  6     private String cloneName;
  7     private String cloneClass;
  8 
  9     public DeepCloneableTarget(String cloneName, String cloneClass) {
 10         this.cloneName = cloneName;
 11         this.cloneClass = cloneClass;
 12     }
 13 
 14     /**
 15      * 因为该类的属性,都是String , 因此我们这里使用默认的clone完成即可
 16      * @return
 17      * @throws CloneNotSupportedException
 18      */
 19     @Override
 20     protected Object clone() throws CloneNotSupportedException {
 21         return super.clone();
 22     }
 23 }
 24 
 25 -----------------------------------------
 26 public class DeepProtoType implements Serializable, Cloneable {
 27 
 28     private static final long serialVersionUID = -948045492482458361L;
 29 
 30     public String name; //String 属性
 31     public DeepCloneableTarget deepCloneableTarget; // 引用类型
 32 
 33     public DeepProtoType() {
 34     }
 35 
 36     /**
 37      * 深克隆,方式1:使用 clone 方法
 38      * @return
 39      * @throws CloneNotSupportedException
 40      */
 41     @Override
 42     protected Object clone() throws CloneNotSupportedException {
 43         Object deep = null;
 44         //这里完成对基本数据类型(属性)和String的克隆
 45         deep = super.clone();
 46         //对引用类型的属性,进行单独处理
 47         DeepProtoType deepProtoType = (DeepProtoType)deep;
 48 
 49         deepProtoType.deepCloneableTarget = (DeepCloneableTarget) deepCloneableTarget.clone();
 50 
 51         return deepProtoType;
 52     }
 53 
 54     /**
 55      * 深拷贝 方式二:通过对象的序列化实现(推荐)
 56      * @return
 57      */
 58     public Object deepClone() {
 59         //创建流对象
 60         ByteArrayOutputStream bos = null;
 61         ObjectOutputStream oos = null;
 62         ByteArrayInputStream bis = null;
 63         ObjectInputStream ois = null;
 64 
 65         try {
 66             //序列化
 67             bos = new ByteArrayOutputStream();
 68             oos = new ObjectOutputStream(bos);
 69             //当前这个对象以对象流的方式输出
 70             oos.writeObject(this);
 71 
 72             //反序列化
 73             bis = new ByteArrayInputStream(bos.toByteArray());
 74             ois = new ObjectInputStream(bis);
 75             DeepProtoType copyObj = (DeepProtoType)ois.readObject();
 76 
 77             return copyObj;
 78         } catch (Exception e) {
 79             e.printStackTrace();
 80             return null;
 81         } finally {
 82             //关闭流
 83             try {
 84                 bos.close();
 85                 oos.close();
 86                 bis.close();
 87                 ois.close();
 88             } catch (IOException e2) {
 89                 System.out.println(e2.getMessage());
 90             }
 91         }
 92     }
 93 }
 94 
 95 ---------------Test测试----------------------
 96 public class Client {
 97 
 98     public static void main(String[] args) throws Exception {
 99         DeepProtoType p = new DeepProtoType();
100         p.name = "宋江";
101         p.deepCloneableTarget = new DeepCloneableTarget("大牛", "小牛");
102 
103         //方式1 完成深拷贝
104 
105         DeepProtoType p2 = (DeepProtoType) p.clone();
106 
107         System.out.println("p.name=" + p.name + "p.deepCloneableTarget=" + p.deepCloneableTarget.hashCode());
108         System.out.println("p2.name=" + p.name + "p2.deepCloneableTarget=" + p2.deepCloneableTarget.hashCode());
109 
110         //方式2 完成深拷贝
111         DeepProtoType p3 = (DeepProtoType) p.deepClone();
112 
113         System.out.println("p.name=" + p.name + "p.deepCloneableTarget=" + p.deepCloneableTarget.hashCode());
114         System.out.println("p2.name=" + p.name + "p2.deepCloneableTarget=" + p3.deepCloneableTarget.hashCode());
115 
116     }
117 }

  更多关于 clone() 的知识  

原文地址:https://www.cnblogs.com/niujifei/p/14249092.html