码迷,mamicode.com
首页 > 其他好文 > 详细

对象复制 - 浅拷贝与深拷贝

时间:2014-12-08 12:00:59      阅读:243      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   io   ar   color   使用   sp   java   

前言

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

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

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

浅拷贝

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

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

如何进行浅拷贝

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

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

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

深拷贝

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

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

如何进行深拷贝

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

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

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

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

代码示例 - 直接赋值

  测试类:

package test;

// 测试类A
public class A {
    public
        // 打印对象内的整型变量值
        void showValueInt() {
            System.out.println(valueInt);
        }
        // 打印对象内的字符串变量值
        void showValueStr() {
            System.out.println(valueStr);
        }
        // 设置对象内的整型变量值
        boolean setValue (int valueInt) {
            this.valueInt = valueInt;
            return true;
        }
        // 设置对象内的字符串变量值
        boolean setValue (String valueStr) {
            this.valueStr = valueStr;
            return true;
        }
    private
        // 值1
        int valueInt;
        // 值2
        String valueStr;
}  

  测试代码:

 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 }

  运行结果

  bubuko.com,布布扣

代码示例 - 浅拷贝

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

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

  运行结果

  bubuko.com,布布扣

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

代码示例 - 深拷贝

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

 1 package test;
 2 
 3 // 测试类A
 4 public class A implements Cloneable {
 5     public
 6         // 实现clone深拷贝方法
 7         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         void showValueInt() {
17             System.out.println(valueInt);
18         }
19         // 打印对象内的字符串变量值
20         void showValueStr() {
21             System.out.println(valueStr);
22         }
23         // 设置对象内的整型变量值
24         boolean setValue (int valueInt) {
25             this.valueInt = valueInt;
26             return true;
27         }
28         // 设置对象内的字符串变量值
29         boolean setValue (String valueStr) {
30             this.valueStr = valueStr;
31             return true;
32         }
33     private
34         // 值1
35         int valueInt;
36         // 值2
37         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 }

  运行结果

  bubuko.com,布布扣

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

小结

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

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

 

对象复制 - 浅拷贝与深拷贝

标签:style   blog   http   io   ar   color   使用   sp   java   

原文地址:http://www.cnblogs.com/scut-fm/p/4150225.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!