zoukankan      html  css  js  c++  java
  • 第三节:浅拷贝和深拷贝

    一、浅拷贝

      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() 的知识  

  • 相关阅读:
    信号
    13. 罗马数字转整数
    ES6基础-constructor与super
    关于antd-vue动态表单的问题以及解决方案
    (vue)关于在ui框架方法中传入多个参数的解决方案
    ts-4: 类型别名与interface
    ts-3:元组与类型约束
    TS-2:类型注释与类型推断、函数参数的定义与返回类型的定义、对象成员与数组成员的定义方法、类型别名与类别名
    LeetCode 141. 环形链表 | Python
    LeetCode 459. 重复的子字符串 | Python
  • 原文地址:https://www.cnblogs.com/niujifei/p/14249092.html
Copyright © 2011-2022 走看看