其實,陣列具有對對象或原始數據類型沒有值,但指針。如果你想要一個詳細的答案,你應該在這裏閱讀我的評論:Java is NEVER pass-by-reference, right?...right?或這裏:In Java, what is a shallow copy?
因此,作爲數組是指針,如果你克隆一個指針指針,它會發生什麼?首先,指針被複製爲真實的,但這些指針只指向其他未被克隆的對象。所以如果你想克隆,我建議不要使用數組,而是使用「更難」的數據結構:類。另一種可能性是永遠不會在數組中存儲數組......就像我僅爲容器使用數組一樣!
但是我不能給你關於Java多維泛型的細節,因爲我從來沒有處理過它們,不僅僅是因爲它們可能不一致,因爲它們是數組(它們違反了一些面向對象原則,使代碼看起來很醜) 。
編輯
我跑了幾個測試的克隆方法的工作原理爲數組類裏面,有什麼問題和變通方法,我們有。
首先,測試數據結構:
public class Foobar implements Cloneable {
String[] array;
public Foobar() {
this.array = new String[10];
}
public String getValue(){
return array[0];
}
public String[] getArray(){
return array;
}
public void setArray(String[] array){
this.array = array;
}
@Override
public Object clone(){
try{
Foobar foobar = (Foobar) super.clone();
foobar.setArray(array);
return foobar;
}
catch(Exception e){
return null;
}
}
}
現在控制器:
String[] array = new String[10];
array[0] = "111";
Foobar foo1 = new Foobar();
foo1.setArray(array);
Foobar foo2 = foo1; //Alternation: Foobar foo2 = (Foobar) foo1.clone();
System.out.println("Instance: "+foo1.getArray()+" with value: "+foo1.getValue());
System.out.println("Instance: "+foo2.getArray()+" with value: "+foo2.getValue());
array[0] = "999";
System.out.println("Instance: "+foo1.getArray()+" with value: "+foo1.getValue());
System.out.println("Instance: "+foo2.getArray()+" with value: "+foo2.getValue());
測試結果總是會這樣的 - 不管我用=或克隆():
Instance: [Ljava.lang.String;@42e816 with value: 111
Instance: [Ljava.lang.String;@42e816 with value: 111
Instance: [Ljava.lang.String;@42e816 with value: 999
Instance: [Ljava.lang.String;@42e816 with value: 999
這是不是好!!
那麼解決方法是什麼?我建議在每一個數據結構類這樣做:
Foobar foo2 = foo1.copy(); //nice and easy!!
這種解決方案的優點:
public class Foobar implements Serializable {
//any class variables...it doesn't matter which!
public Foobar() {
//do initialisation here...it doesn't matter what you do!
}
public Foobar copy(){
try{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
Foobar foobar = (Foobar) ois.readObject();
return foobar;
}
catch(Exception e){
return null;
}
}
}
所以,你將通過實施只用一行代碼得到一個完整拷貝它通常足以實現Serializable接口來創建一個「可複製」的類。如果沒有,您可以通過閱讀Serializable Javadoc中編寫的內容來解決任何問題!
甚至更多:無論您要製作「可複製」的課程中的什麼類型的對象,都無需在此問題上花費更多時間。畢竟,上面的代碼是迄今爲止深入嵌入Java的最簡單且最快的解決方案,並且僅使用RAM! (感謝ByteArrayOutputStream)
享受!
更新:請注意,如果您想要臨時堆棧或者如果您要處理線程(通常:如果您需要使對象完全獨立),則只需要使用對象的副本。否則,你不應該做任何複製!另外,如果您將一些數據寫入文件或套接字中,則不需要副本。甚至更多我建議只在真正使用時才實現複製方法:用於數據結構(模型)。所以使用這個強大的方法時要小心(否則它可能會減慢你的應用程序的速度,或者如果你無緣無故地製作數百萬份拷貝,甚至會填滿Java VM存儲空間,這確實會導致stackoverflow:o)。
編輯
我工作多一點就這一問題。因爲我突然發現,有一個公共clone()方法的「原始」數組不在Java API中! (來自SUN的「復活節彩蛋」,用於像String []或int [];]的數組
而且我使用實數組作爲Foobar的基本數據結構(不是ArrayLists!),我可以這樣改變的克隆方法(以上級):
@Override
public Object clone(){
try{
Foobar foobar = (Foobar) super.clone();
String[] arrayClone = array.clone(); //who thought that this is possible?!
foobar.setArray(arrayClone);
return foobar;
}
catch(Exception e){
return null;
}
}
現在,我們得到這樣的結果右側開箱:
Instance: [Ljava.lang.String;@42e816 with value: 111
Instance: [Ljava.lang.String;@9304b1 with value: 111
Instance: [Ljava.lang.String;@42e816 with value: 999
Instance: [Ljava.lang.String;@9304b1 with value: 111
問題與解決「雙嵌套「對象!!!正如你所看到的,克隆有獨立於原始的不同對象,因此foo1.equals(foo2))將是錯誤的!
解決方案:在類的克隆方法中,您也需要克隆其所有類變量!(但是,如果某些類變量是ArrayLists或更多維數組,則即使此解決方案也行不通!)
最後,真正的問題是什麼?類ArrayList不克隆它的數組,它只調用類Array中的方法copyOf,這是有害的。 因此,切勿使用類ArrayList的克隆方法,也不要從ArrayList繼承任何類,因爲它的克隆方法不起作用!(它只有在類ArrayList只包含原語並且沒有對象的情況下才起作用,否則只需使用上面簡單的ByteArray解決方案!)。
請注意,對於像Object [] []這樣的更多維數組,您總是需要實現上面的ByteArray解決方案,它們不能被克隆!如果你的陣列很大,可能需要一段時間,並且需要一些RAM。
現在你是克隆專家! :-D
Java中的多維數組是指向數組的指針數組。克隆只會克隆第一個數組。 – 2012-03-16 12:33:16
那麼我該如何做到這一點?我是否需要製作一個將原始int從一個數組複製到另一個數組的循環? – AndreiBogdan 2012-03-16 12:33:51
您需要製作一個克隆內部陣列的循環。或者在Arrays類中可能會有這樣一個功能 - 自從它發明以來,我沒有真正研究這個類。 – 2012-03-16 15:19:38