zoukankan      html  css  js  c++  java
  • 对象复制

    前言

      在前面的文章中,提到过Java之间如果发生了对象赋值,那么其意义是赋值的两个对象都指向同一片内存区域。

      那么,如果我希望得到的是一份新的副本 - 即可以随意更改而不影响原始对象呢?

      那就涉及到本文要探讨的话题 - 对象的浅拷贝与深拷贝。

    浅拷贝

      若对象之间发生浅拷贝,那么首先肯定的是会创建一个新的对象副本(这就不同与对象间的直接赋值).

      然后所有域进行简单的直接复制 - 非对象域直接拷贝过来,对象域则拷贝此对象的地址(因为对象在java中的本质就是一个 "指针")

    如何进行浅拷贝

      1. 为目标类继承Cloneable接口。

      2. 使用public访问修辞符重新定义clone方法且抛出CloneNotSupportedException异常。

      3. 在clone方法中调用父类的clone方法并将结果强制转型为当前类类型后返回。

    深拷贝

      看完了浅拷贝,你很有可能对其处理对象域的操作不满意。因为对象如果直接拷贝地址过来,则副本中该对象域的改变势必也会影响到原始对象中的对象域。

      相对于浅拷贝,深拷贝是指用户自定义对象域的拷贝方式。

    如何进行深拷贝

      1. 为目标类继承Cloneable接口。

      2. 使用public访问修辞符重新定义clone方法且抛出CloneNotSupportedException异常。

      3. 在clone方法中调用父类的clone方法并将结果强制转型为当前类类型。

      4. 对3中处理得到的结果以自定义的方式拷贝对象域部分。

    代码示例 - 直接赋值

      测试类:

     1 package test;
     2 
     3 // 测试类A
     4 public class A {
     5     
     6     // 打印对象内的整型变量值
     7     public void showValueInt() {
     8         System.out.println(valueInt);
     9     }
    10     // 打印对象内的字符串变量值
    11     public void showValueStr() {
    12         System.out.println(valueStr);
    13     }
    14     // 设置对象内的整型变量值
    15     public boolean setValue (int valueInt) {
    16         this.valueInt = valueInt;
    17         return true;
    18     }
    19     // 设置对象内的字符串变量值
    20     public boolean setValue (String valueStr) {
    21         this.valueStr = valueStr;
    22         return true;
    23     }
    24     
    25     // 值1
    26     private int valueInt;
    27     // 值2
    28     private String valueStr;
    29 }

      测试代码:

     1 package test;
     2 
     3 public class Java7Learn {
     4     
     5     public static void main(String[] args){
     6         
     7         // 创建一个对象a1,并让它直接赋值给a2。
     8         A a1 = new A();
     9         A a2 = a1;
    10         
    11         // 设置a1的两个变量值并打印出来
    12         a1.setValue(1);
    13         a1.setValue("this is a1");
    14         a1.showValueInt();
    15         a1.showValueStr();
    16         
    17         // 设置a2的两个变量值并打印出来
    18         a2.setValue(2);
    19         a2.setValue("this is a2");
    20         a2.showValueInt();
    21         a2.showValueStr();
    22         
    23         // 显示结果发现 - a1的对象值都变成a2的了。
    24         a1.showValueInt();
    25         a1.showValueStr();
    26     }    
    27 }

      运行结果

      

    代码示例 - 浅拷贝

      首先按照前文所讲的浅拷贝的方法修改测试类:

     1 package test;
     2 
     3 // 测试类A
     4 public class A implements Cloneable {
     5     
     6      // 实现clone浅拷贝方法
     7     public A clone() throws CloneNotSupportedException
     8     {
     9         return (A)super.clone();
    10     }
    11     // 打印对象内的整型变量值
    12     public void showValueInt() {
    13         System.out.println(valueInt);
    14     }
    15     // 打印对象内的字符串变量值
    16     public void showValueStr() {
    17         System.out.println(valueStr);
    18     }
    19     // 设置对象内的整型变量值
    20     public boolean setValue (int valueInt) {
    21         this.valueInt = valueInt;
    22         return true;
    23     }
    24     // 设置对象内的字符串变量值
    25     public boolean setValue (String valueStr) {
    26         this.valueStr = valueStr;
    27         return true;
    28     }
    29     
    30     // 值1
    31     private int valueInt;
    32     // 值2
    33     private String valueStr;
    34 }

      测试代码:

    package test;
    
    public class Java7Learn {
        
        public static void main(String[] args) throws CloneNotSupportedException{
            
            // 创建一个对象a1,并将它克隆到a2。
            A a1 = new A();
            A a2 = a1.clone();
            
            // 设置a1的两个变量值并打印出来
            a1.setValue(1);
            a1.setValue("this is a1");
            a1.showValueInt();
            a1.showValueStr();
            
            // 设置a2的两个变量值并打印出来
            a2.setValue(2);
            a2.setValue("this is a2");
            a2.showValueInt();
            a2.showValueStr();
            
            // 显示结果发现 - a1的整型对象值没变,但字符串型的变了。
            a1.showValueInt();
            a1.showValueStr();
        }    
    }

      运行结果

      

      发现,a1的整型对象值没变,但字符串型的变了。这是和预期相一致的。

    代码示例 - 深拷贝

      首先按照前文所讲的深拷贝的方法修改测试类:

     1 package test;
     2 
     3 // 测试类A
     4 public class A implements Cloneable {
     5     
     6     // 实现clone深拷贝方法
     7     public A clone() throws CloneNotSupportedException
     8     {
     9         A cloned = (A)super.clone();
    10         // 自定义拷贝方式。
    11         // 一般定义的方式都是调用成员自己的clone函数。但测试的字符串默认赋值会深拷贝,就没有在这里继续clone了。
    12         cloned.valueStr = valueStr;
    13         return cloned;
    14     }
    15     // 打印对象内的整型变量值
    16     public void showValueInt() {
    17         System.out.println(valueInt);
    18     }
    19     // 打印对象内的字符串变量值
    20     public void showValueStr() {
    21         System.out.println(valueStr);
    22     }
    23     // 设置对象内的整型变量值
    24     public boolean setValue (int valueInt) {
    25         this.valueInt = valueInt;
    26         return true;
    27     }
    28     // 设置对象内的字符串变量值
    29     public boolean setValue (String valueStr) {
    30         this.valueStr = valueStr;
    31         return true;
    32     }
    33     
    34     // 值1
    35     private int valueInt;
    36     // 值2
    37     private String valueStr;
    38 }

      测试代码:

     1 package test;
     2 
     3 public class Java7Learn {
     4     
     5     public static void main(String[] args) throws CloneNotSupportedException{
     6         
     7         // 创建一个对象a1,并将它克隆到a2。
     8         A a1 = new A();
     9         A a2 = a1.clone();
    10         
    11         // 设置a1的两个变量值并打印出来
    12         a1.setValue(1);
    13         a1.setValue("this is a1");
    14         a1.showValueInt();
    15         a1.showValueStr();
    16         
    17         // 设置a2的两个变量值并打印出来
    18         a2.setValue(2);
    19         a2.setValue("this is a2");
    20         a2.showValueInt();
    21         a2.showValueStr();
    22         
    23         // 显示结果发现 - a1的所有对象值都没被影响。
    24         a1.showValueInt();
    25         a1.showValueStr();
    26     }    
    27 }

      运行结果

      

      a2所做的操作完全没有影响a1的域。

    小结

      1. 要清晰区分对象直接赋值,浅拷贝,深拷贝这三者的底层机制。

      2. clone的方式确实有点 "笨重",但必须严格的遵守才能写出高质量的代码。

  • 相关阅读:
    SAP BW 例程(Routine)【开始例程、关键值或特性的例程、结束例程】
    sap 提取字符串中汉字
    判断当前一个物料被其他人锁定
    ABAP "FOR ALL ENTRIES IN" 使用指南
    ABAP检查日期and时间合法性的函数
    READ语句相关
    QUERY客户出口变量的I_STEP解释
    Abap 内表的语法
    Ancient Knight(打造Windows Mobile平台最专业的游戏修改器)
    VC通用控件自适应屏幕类
  • 原文地址:https://www.cnblogs.com/scut-fm/p/4150225.html
Copyright © 2011-2022 走看看