标签: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 }
运行结果
代码示例 - 浅拷贝
首先按照前文所讲的浅拷贝的方法修改测试类:
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(); } }
运行结果
发现,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 }
运行结果
a2所做的操作完全没有影响a1的域。
小结
1. 要清晰区分对象直接赋值,浅拷贝,深拷贝这三者的底层机制。
2. clone的方式确实有点 "笨重",但必须严格的遵守才能写出高质量的代码。
标签:style blog http io ar color 使用 sp java
原文地址:http://www.cnblogs.com/scut-fm/p/4150225.html