熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java高級技術 >> 正文

詳細講述Java中的克隆

2013-11-23 19:42:37  來源: Java高級技術 

  經常聽到有人說java中沒有指針事實如此嗎?nojava是有指針的只不過換了個名字而已也就是我們經常提到的引用我們知道在java中一切都是對象那麼我們如何操控對象?如何在成千上萬的對象中找到我們所需的那個對象呢?又是如何讓對象按照我們的意思來完成任務的呢?

  Object o = new Object()

  這是java中最常見的語句了在這句話中做了三件事首先聲明一個Object類型的變量o在內存中為對象劃分一塊地址new Object()將聲明的變量指向內存中的對象如此一來我們就可以通過o來操縱對象了就好像孩子們玩的遙控飛機在空中飛行的是飛機而使它做出優美動作的卻是孩子們手中的搖控器

  克隆是如今聽到的較多的詞匯聽說已經將某只羊克隆了好幾份了但願這種技術不要在人身上實驗java中也有克隆與現實世界的克隆一樣將一個實際存在的對象拷貝幾份如下

  

  //倒霉的羊
public class Sheep implements Cloneable{
private String name;
public void setName(String arg) {
name = arg;
}
public String getName() {
return name;
}
public Object clone() throws CloneNotSupportedException {
return superclone();
}
}
//克隆
public class Main {
public static void main(String[] args) throws CloneNotSupportedException {
Sheep sheep = new Sheep(); //先得到那只羊的實例
sheepsetName(我是真的); //給它做個記號
Systemoutprintln(sheepgetName() = + sheepgetName());
Sheep sheepClone = (Sheep)sheepclone(); //開始克隆
Systemoutprintln(sheepClonegetName() = + sheepClonegetName());
}
}

  運行程序結果為

  sheepgetName() = 我是真的

  sheepClonegetName() = 我是真的

  兩只羊是一模一樣的(哪怕那只羊瘸腿)讓我們來看看代碼首先要注意的是Sheep類實現了Cloneable接口(該接口屬於javalang包默認已經導入了)該接口中並沒有定義要實現的方法是個空接口起標志作用也就是說實現了這個接口的羊就不再是只普通的羊它是一只可以被克隆的羊再往下看有個clone方法返回Object類型的對象並拋出CloneNotSupportedException異常該方法覆寫了父類 (Object)的clone方法並在最後調用了superclone()這也意味著無論clone類繼承結構是什麼樣的superclone ()都會直接或間接調用Object類的clone()方法看看jdk幫助文檔會發現Object類的clone()是一個native方法我們知道native方法的效率一般來說都是遠高於java中的非native方法這也說明了new一個對象然後將原對象中的數據導入到新創建的對象中去的做法是多麼愚蠢必須說明的是Object中的clone方法是protected的所以要使用clone就必須繼承Object類(默認)並且為了可以使其它類調用該方法必須將其作用域設置為public

  以上只是一個簡單clone的實現明天說說影子clone深度clone

  夜深了何為影子clone?先看一下例子

  

  //倒霉的羊
public class Sheep implements Cloneable{
private String name;
public void setName(String arg) {
name = arg;
}
public String getName() {
return name;
}
public Object clone() throws CloneNotSupportedException {
return superclone();
}
}
//羊圈
public class Sheepfold implements Cloneable {
public Sheep sheep;
public String name;
public Sheepfold() {
sheep = new Sheep();
}
public Object clone() throws CloneNotSupportedException {
return superclone();
}
}
//克隆
public class Main {
public static void main(String[] args) throws Exception {
Sheepfold fold = new Sheepfold();
foldname = 小羊圈;
foldsheepsetName(小羊);
Sheepfold fold = (Sheepfold)foldclone();
Systemoutprintln( foldname = + foldname);
Systemoutprintln( foldsheepgetName() = + foldsheepgetName());
foldname = 大羊圈;
foldsheepsetName(大羊);
Systemoutprintln(=====================================);
Systemoutprintln( foldname = + foldname);
Systemoutprintln(* foldsheepgetName() = + foldsheepgetName());
Systemoutprintln( foldname = + foldname);
Systemoutprintln(* foldsheepgetName() = + foldsheepgetName());
Systemoutprintln(=====================================);
}
}

  在這個例子中有三個類Sheep和Sheepflod都實現了Cloneable接口並且覆寫了Object類的clone方法說明這兩個類是具有克隆能力的注意一點在Sheepflod中持有一個Sheep的實例並在Main類中對其進行克隆結果如下

  

  請注意一下結果中帶有*號的兩條結果語句foldsheep和foldsheep的name都變為了大羊很奇怪是嗎?在此之前我們只對foldsheep的name賦過值為什麼foldsheep的name也變為了大羊呢?原因很簡單因為它們是指向同一個對象的不同引用從中可以看出調用Object類中clone()方法時首先在內存中劃分一塊同原對象相同的空間然後將原對象的內容原樣拷貝至新對象我們知道java中有基本數據類型對於基本數據類型這樣的操作是沒有問題的但對非基本類型變量它們保存的僅僅是對象的引用這也是為什麼clone後非基本類型變量和原對象中的變量指向同一個對象的原因可能你已經注意到程序中用到了String類型即對象為什麼沒有出現引用指向同一地址的情況?這是因為String是一個不可更改的類(immutable class)每次給它賦值時都會產生一個新的String對象如 String str = a str += b在這兩句代碼中當執行str += b實際上是重新成生了一個值為ab的 String對象即重新分配了一塊內存空間以上clone方法通常被稱為影子clone影子clone給我們留下了一個問題即多個引用指向同一個對象如何解決該問題呢?答案為深度clone把上面的例子改成深度clone很簡單只需將Sheepfold的clone()方法改為如下即可很簡單只需將Sheepfold的clone()方法改為如下即可

  

  public Object clone() throws CloneNotSupportedException {
Sheepfold fold = (Sheepfold)superclone();
sheep = (Sheep)foldsheepclone();
return fold;
}


From:http://tw.wingwit.com/Article/program/Java/gj/201311/27342.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.