您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“Java對(duì)象克隆怎么實(shí)現(xiàn)”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“Java對(duì)象克隆怎么實(shí)現(xiàn)”吧!
1. Overiew
在實(shí)際編程中,我們經(jīng)常會(huì)遇到這樣一個(gè)情景:有一個(gè)對(duì)象A,存在屬性方法,現(xiàn)在需要一個(gè)和A完全相同的新對(duì)象B,并且B的任何改動(dòng)都不會(huì)影響到A中的值。那么,最常用的辦法就是對(duì)A進(jìn)行克隆。
2. How to Clone
在java.lang.Object中有一個(gè)clone方法,該方法的簽名如下:
Java代碼
protected native Object clone() throws CloneNotSupportedException;
該方法返回一個(gè)Object實(shí)例的拷貝,該實(shí)例拷貝具有:
1)拷貝對(duì)象是一個(gè)新對(duì)象而不是一個(gè)原對(duì)象引用。
2)拷貝的對(duì)象中包含的是原有對(duì)象信息,而不是對(duì)象初始化的信息(也就是說(shuō),拷貝過(guò)程沒(méi)有調(diào)用構(gòu)造函數(shù))。
從第1條我們可以看出,拷貝的對(duì)象與原對(duì)象存在這樣一種關(guān)系:
Java代碼
1. x.clone() != x will be true 2. x.clone().getClass() == x.getClass() will be true, but these are not absolute requirements 3. x.clone().equals(x) will be true, but these are not absolute requirements
要實(shí)現(xiàn)克隆,必須滿足一下三點(diǎn):
1)類必須實(shí)現(xiàn)Cloneable接口
2)類必須重載Object類中的clone()方法
3)重載的clone()方法中,必須顯示調(diào)用super.clone()。
我們看一下Cloneable接口的定義:
Java代碼
public interface Cloneable { }
Cloneable接口是不包含任何方法的,僅僅表示一個(gè)標(biāo)志(類似Serializable接口),而且這個(gè)標(biāo)志也是針對(duì)Object類中clone()方法的,如果clone類沒(méi)有實(shí)現(xiàn)Cloneable接口,并調(diào)用了Object的clone()方法(也就是調(diào)用了super.Clone()方法),那么Object的clone()方法就會(huì)拋出CloneNotSupportedException異常。
按照要求,我們寫一個(gè)克隆類的小例子:
Java代碼
public class DummyClone implements Cloneable{ public Object clone(){ DummyClone dc = null; try { dc = (DummyClone)super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return dc; } }
3. Shadow Clone
首先,我們來(lái)看一個(gè)例子:ClassA沒(méi)有實(shí)現(xiàn)Cloneable接口。ClassB存在ClassA的實(shí)例,實(shí)現(xiàn)了Cloneable接口,并重載了clone方法。ClassC實(shí)例化一個(gè)ClassB對(duì)象,然后克隆一個(gè)對(duì)象。
Java代碼
class ClassA { public int a; public void doubleA(){ a = a * 2; } public ClassA(int aa){ this.a = aa; } public String toString(){ return Integer.toString(a); } } class ClassB implements Cloneable{ public int b; public ClassA ca = new ClassA(11); public Object clone(){ ClassB cb = null; try { cb = (ClassB)super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return cb; } } public class ClassC { public static void main(String[] args) { ClassB cb = new ClassB(); cb.b = 222; System.out.println("before clone : cb.b = " + cb.b); System.out.println("before clone : cb.ca = " + cb.ca); // ClassB cb2 = (ClassB)cb.clone(); cb2.b = 3333; cb2.ca.doubleA(); System.out.println("========================"); System.out.println("after clone : cb.b = " + cb.b); System.out.println("after clone : cb.ca = " + cb.ca); System.out.println("========================"); System.out.println("after clone : cb2.b = " + cb2.b); System.out.println("after clone : cb2.ca = " + cb2.ca); } }
輸出結(jié)果如下:
Java代碼
before clone : cb.b = 222 before clone : cb.ca = 11 ======================== after clone : cb.b = 222 after clone : cb.ca = 22 ======================== after clone : cb2.b = 3333 after clone : cb2.ca = 22
從結(jié)果我們看到,int類型的b被完全的克隆了,而ClassA類型的ca卻沒(méi)有被克隆。因?yàn)榭寺『骳b2對(duì)b的賦值不會(huì)影響原有cb中b的值,而調(diào)用cb2.ca.doubleA()方法后,對(duì)cb2.ca的改變同時(shí)改變了cb.ca,表明cb2.ca與cb.ca僅僅指向同一個(gè)對(duì)象的不同引用。從中可以看出,調(diào)用Object類中clone()方法產(chǎn)生的效果是:先在內(nèi)存中開辟一塊和原始對(duì)象一樣的空間,然后原樣拷貝原始對(duì)象中的內(nèi)容。對(duì)基本數(shù)據(jù)類型,這樣的操作是沒(méi)有問(wèn)題的,但對(duì)非基本類型變量clone后的變量和原始對(duì)象中相應(yīng)的變量指向的是同一個(gè)對(duì)象。
這就是影子克隆。影子克隆,并沒(méi)有完整的完成克隆,有時(shí)候這并不是我們想要的結(jié)果。我們有時(shí)需要,就像列子中調(diào)用cb2.ca.doubleA()方法時(shí),不會(huì)對(duì)原對(duì)象產(chǎn)生改變,這時(shí)候我們就需要deep clone;
4. Deep Clone
要實(shí)現(xiàn)深度克隆,在上面的例子基礎(chǔ)上,我們只需要這樣修改即可:
Java代碼
class ClassA implements Cloneable{ public int a; public void doubleA(){ a = a * 2; } public ClassA(int aa){ this.a = aa; } public String toString(){ return Integer.toString(a); } public Object clone(){ ClassA ca = null; try { ca = (ClassA)super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return ca; } } class ClassB implements Cloneable{ public int b; public ClassA ca = new ClassA(11); public Object clone(){ ClassB cb = null; try { cb = (ClassB)super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } cb.ca = (ClassA)ca.clone(); return cb; } } public class ClassC { public static void main(String[] args) { ClassB cb = new ClassB(); cb.b = 222; System.out.println("before clone : cb.b = " + cb.b); System.out.println("before clone : cb.ca = " + cb.ca); // ClassB cb2 = (ClassB)cb.clone(); cb2.b = 3333; cb2.ca.doubleA(); System.out.println("========================"); System.out.println("after clone : cb.b = " + cb.b); System.out.println("after clone : cb.ca = " + cb.ca); System.out.println("========================"); System.out.println("after clone : cb2.b = " + cb2.b); System.out.println("after clone : cb2.ca = " + cb2.ca); } }
輸出結(jié)果:
Java代碼
before clone : cb.b = 222 before clone : cb.ca = 11 ======================== after clone : cb.b = 222 after clone : cb.ca = 11 ======================== after clone : cb2.b = 3333 after clone : cb2.ca = 22
基本的數(shù)據(jù)類型可以自動(dòng)的實(shí)現(xiàn)深度的克隆,然而并不是所有的類都可以進(jìn)行深度的克隆,就比如String類,其類定義為final,且沒(méi)有重載clone方法,我們就無(wú)法完成對(duì)String類的深度克隆。關(guān)于不可變對(duì)象的克隆,我們通常沒(méi)有必要去克隆。
到此,相信大家對(duì)“Java對(duì)象克隆怎么實(shí)現(xiàn)”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。