Java中克隆的用法,深拷贝、浅拷贝概念的引出
一 什么是克隆
克隆就是根據(jù)已有對象復(fù)制出另一個(gè)對象。比如用A克隆出B,一般在java中有如下約定:
// A與B的引用不同 A!=B // A與B的類相同 A.getClass == B.getClass // A和B內(nèi)容相同 A.equals(B)通常來說 A.equals(B) == true,但是這不是強(qiáng)制的要求,開發(fā)人員可根據(jù)具體需要決定是否重寫equals方法。二 怎么實(shí)現(xiàn)克隆
需要克隆的類 實(shí)現(xiàn) Cloneable 接口,并重寫其中的clone方法。其中super.clone()會(huì)把原始對象的屬性克隆到新對象的屬性中。
public class Student1 implements Cloneable{private String name;private int age;public Student1(String name, int age) {this.name = name;this.age = age;}@Overrideprotected Student1 clone() throws CloneNotSupportedException {return (Student1)super.clone();} }測試程序如下:
public class TestClone {public static void main(String[] args) {Student1 xiaoming = new Student1(new String("小明"),12);Student1 xiaoming_Copy = null;try {xiaoming_Copy = xiaoming.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}System.out.println(xiaoming.toString());System.out.println(xiaoming_Copy.toString());} }輸出:
{“age”:12,”name”:”小明”}
{“age”:12,”name”:”小明”}
這樣Student的克隆成功了。
實(shí)際上,Cloneable是個(gè)空接口,它沒有定義任何成員。它只是一個(gè)對象可重寫并使用clone方法的標(biāo)志。
public interface Cloneable { }三 這樣就結(jié)束了嗎??
如果一個(gè)類中的域(屬性)都是基本數(shù)據(jù)類型或者final類型當(dāng)然就沒有問題了,但是如果一個(gè)類的域是非final類型的引用類型(比如:數(shù)組、其他對象)。那么這樣克隆就會(huì)出現(xiàn)一個(gè)問題,先看一個(gè)例子:
新加了一個(gè)Teacher類:
Stuent類中加入Teacher屬性:
public class Student2 implements Cloneable {private String name;private int age;private Teacher teacher;public Student2(String name, int age, Teacher teacher) {this.name = name;this.age = age;this.teacher = teacher;}@Overrideprotected Student2 clone() throws CloneNotSupportedException {return (Student2)super.clone();}運(yùn)行下面的測試程序:
public class TestClone {public static void main(String[] args) {Teacher teacher = new Teacher("王尼瑪",41);Student2 xiaoming = new Student2(new String("小明"),12,teacher);Student2 xiaoming_Copy = null;try {xiaoming_Copy = xiaoming.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}xiaoming_Copy.getTeacher().setName("齊東強(qiáng)");System.out.println(xiaoming.toString());System.out.println(xiaoming_Copy.toString());} }輸出
{“age”:12,”name”:”小明”,”teacher”:{“age”:41,”name”:”齊東強(qiáng)”}}
{“age”:12,”name”:”小明”,”teacher”:{“age”:41,”name”:”齊東強(qiáng)”}}
發(fā)現(xiàn)拷貝對象副本在改變自己屬性的時(shí)候會(huì)影響原始主本的數(shù)據(jù),這是因?yàn)閟uper.clone()只會(huì)把Student中對Teacher的引用值copy給克隆對象。所以主本和副本中的teacher對象指向了相同的堆地址。顯然這不是我們想要的。
四 如何解決
嵌套多少層非final類型的引用,我們就拷貝多少層!
Teacher也 實(shí)現(xiàn) Cloneable類,添加clone方法
修改Student中的clone方法為:
@Overridepublic Student2 clone() throws CloneNotSupportedException {Student2 copy = (Student2)super.clone();copy.teacher = teacher.clone();return copy;}再次運(yùn)行測試程序
{“age”:12,”name”:”小明”,”teacher”:{“age”:41,”name”:”王尼瑪”}}
{“age”:12,”name”:”小明”,”teacher”:{“age”:41,”name”:”齊東強(qiáng)”}}
這次修改克隆對象的引用屬性,原對象就不會(huì)被改變了
五 總結(jié)
其實(shí)三中的demo被稱為淺克隆(淺拷貝),四中的解決方案為深克隆(深拷貝)
5.1 淺拷貝
淺拷貝是指拷貝對象時(shí)僅僅拷貝對象本身(包括對象中的基本變量),而不拷貝對象包含的非final引用類型屬性指向的對象
public Object clone() {return super.clone();}直接使用super.clone()方法。
5.2 深拷貝
深拷貝不僅拷貝對象本身,而且拷貝對象包含的引用指向的所有對象
public Object clone() {Object obj = super.clone();//先淺拷貝一下//然后修正需要修正的屬性obj.屬性1 = xxx;obj.屬性2 = xxx;...}5.3 如何選擇使用哪種拷貝方式
1.如果類中的屬性只包含有基本數(shù)據(jù)類型或常量(包括String),那么這個(gè)類使用淺拷貝。
使用淺拷貝的類也可能需要修正,譬如代表序列號(hào)、其他唯一ID、對象的創(chuàng)建時(shí)間的屬性,不管這些屬性是基本類型還是常量,都需要修正。(常量需要修正時(shí),不能使用super.clone())
2.如果類中的屬性包含有非final的引用類型時(shí)(String不算),使用深拷貝,不然拷貝對象的改變會(huì)影響原對象,就失去了拷貝的意義。
5.4 什么時(shí)候使用克隆
總結(jié)
以上是生活随笔為你收集整理的Java中克隆的用法,深拷贝、浅拷贝概念的引出的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 正面硬刚Beats!这款耳机从美国红回中
- 下一篇: 盘点互联网大佬背后的女人,最后一个你肯定