2013-08-21 20 views
15

關於Arrays.copyOf是否會產生深層或淺層副本,似乎存在很多混淆和不同觀點([1]和其他來源)。是否Arrays.copyOf產生淺或深的副本?

該測試表明,副本是深:

String[] sourceArray = new String[] { "Foo" }; 
String[] targetArray = java.util.Arrays.copyOf(sourceArray, 1); 

sourceArray[0] = "Bar"; 

assertThat(targetArray[0]).isEqualTo("Foo"); // passes 

該測試表明,副本是淺:

String[][] sourceArray = new String[][] { new String[] { "Foo" } }; 
String[][] targetArray = java.util.Arrays.copyOf(sourceArray, 1); 

sourceArray[0][0] = "Bar"; 

assertThat(targetArray[0][0]).isEqualTo("Foo"); // fails 

是解決方案僅僅是頂級尺寸的深副本是製作的,但其他尺寸是淺拷貝?真相是什麼?

[1] How do I do a deep copy of a 2d array in Java?

+0

也許只是字符串 – Matthias

+0

@Matthias的實習的另一occurence。由於「Foo」是一個字面意思,它將被實施;測試假設。如果這個假設是正確的,那麼測試調查是否目標元素已被'=「酒吧」'的相應的源元素改變。 – ToolmakerSteve

+0

我沒有看到測試對字符串是否內化做出任何假設。我沒有看到任何身份測試,我只看到平等測試。對於淺拷貝和深拷貝,結果將是相同的,因爲淺拷貝和深拷貝之間的相等性檢驗不能不同。一個需要身份測試來區分淺拷貝和深拷貝。 –

回答

22

它產生淺拷貝,即包含「老」的引用一個陣列(以相同的目的,那些沒有被複制)。

特別是,如果您有嵌套數組,那些將不會被複制。您將獲得一個新的陣列,其「頂層」指向與原始陣列相同的「二級」陣列。這些嵌套數組內的任何更改都將反映在副本和原始數據中。

該測試表明,副本是深:

不,不。將新對象分配給「原始」陣列時,這不會影響副本。畢竟,它是一個副本。

這是同樣的情況:

String x = "foo"; 
String y = x; 
x = "bar"; 

assertEquals(y, "foo"); 

否 「深拷貝」 在這裏。

4

表格Java Doc

....兩個陣列將包含相同的值。

所以在包含引用的數組的情況下,只複製引用而不是實際的對象。這意味着淺拷貝。

-4

這是一個深層複製。它在字符串的情況下顯得很淺,因爲在封面下,字符串是單例。 JVM有一個用於字符串的內存池,並且每個唯一字符串只有一個副本。所以你總是得到該字符串引用的副本。下面的示例顯示爲類Object創建了一個深層副本。當原始數組發生更改時,副本不會更改。

公共類ArrayTest中{

public static void main(String [] args) { 
    Object [] objs = new Object[1]; 
    objs[0] = new Object(); 
    System.out.println("Original: " + objs[0].toString()); 

    Object [] copy = java.util.Arrays.copyOf(objs, 1); 
    objs[0] = new Object(); 
    System.out.println("copy, after original reassigned: " + 
    copy[0].toString()); 
    System.out.println("Original, after reassigned: " + 
    objs[0].toString()); 
} 

}

+1

這不是一個深層副本,深層副本需要複製存儲在數組中的所有對象本身。 Arrays.copyOf不這樣做;它只是簡單地複製引用 - 即淺拷貝 –

+0

另外,爲什麼字符串數組的行爲與其他對象的行爲不同的說法簡直是錯誤的。是的,字符串文字是interned。不,這不會導致字符串的行爲與任何其他(引用)對象的行爲不同。可能這個回答者被問題代碼對文字的字符串實習的依賴所誤導,這對於第一次測試的通過是必要的。如果將「Foo」放入一個變量,然後在任何地方使用該變量,問題就會變得更加清晰。 – ToolmakerSteve

+0

很抱歉地說,你的答案不止一種。副本是淺拷貝。字符串並不總是內在化的,只有在特殊情況下。例如,在'String foo =「Foo」中; String foo2 = new String(foo);','foo2'指向一個新的副本。並且不可能從重寫的Object.equals()方法推斷複製是深度還是淺度,因爲這是'Object.equals()'爲每個定義隱藏的東西。 –

1

「淺」或「深」 - 這是我看到沒有一個精確定義的問題 - 在實踐中Arrays.copyOf(..)所做的方法產生一個副本源數組的更改不受源數組更改的影響。

看看下面簡單的例子爲int數組:

import java.util.Arrays; 

public class DeepCopyTest 
{ 

    public static void main(String[] args) 
    { 
     int[] source = { 1, 2, 3, 4, 5, 6}; 
     int[] target = new int[source.length]; 
     // Copy target from source via Arrays.copyOf(..) method : 
     target = Arrays.copyOf(source, 6); 
     // Check for equality : 
     System.out.println("Source1 : " + Arrays.toString(source)); 
     System.out.println("Target1 : " + Arrays.toString(target)); 
     // Increment all entries in source array : 
     for(int i = 0; i < source.length; i++) 
     { 
      source[i] = source[i] +1; 
     } 
     // See if target is affected : 
     System.out.println("Source2 : " + Arrays.toString(source)); 
     System.out.println("Target2 : " + Arrays.toString(target)); 

    } 

} 

// OUTPUT 
// ------ 
Source1 : [1, 2, 3, 4, 5, 6] 
Target1 : [1, 2, 3, 4, 5, 6] 
Source2 : [2, 3, 4, 5, 6, 7] 
Target2 : [1, 2, 3, 4, 5, 6] 

實際上,當人們尋求一個數組的「深層複製」,他們只是想要的東西,是改變原來未受影響。

而這個Arrays.copyOf(..)`方法確實給了它們。

除了原始類型陣列,字符串對象陣列也表現爲上述實例中,給予像輸出:

Source1 : [a, b, c, d, e, f] 
Target1 : [a, b, c, d, e, f] 
Source2 : [a1, b1, c1, d1, e1, f1] 
Target2 : [a, b, c, d, e, f] 

當初始源陣列條目由「1」串聯。

它也適用於對象數組,因爲當後者被重新分配時,目標不再與源相關聯。 但看輸出複印後兩個陣列的第一個元素,然後改變源後[0]揭示了充分的事實:

Source1 : [email protected] 
Target1 : [email protected] 
Source2 : [email protected] 
Target2 : [email protected] 

原始源陣列被複制之後,目標元件簡單地被指出無論目前在源代碼中有哪些價值。對於目標[0],它是內存地址1db9742的內容 - 也是保存源[0]的相同內存地址。 。 。 。

而我們得到源[0]重新分配後,源和目標之間的剝離的原因是由於一個事實,即賦值語句

source[0] = new Object(); 

只是導致源舉行的內存引用[0]到當一個新的對象被指向時被改變到一個新的位置。 因此,儘管在很多情況下它賦予編碼員與深度複製相同的好處,但它畢竟不是純粹意義上的真正深層複製。

隨着原始數據的陣列中的Arrays.copyOf(..)方法不能複製,因爲這些參考文獻都沒有用於原語。它只是將源元素值複製到目標元素中。我們再次獲得與深拷貝相同的效果,代價是代碼少於深拷貝的操作。

因此,Arrays.copyOf(..)是原始和一維對象數組的一種'廉價'深拷貝。 但是,任何數據數組更復雜,它被發現。

也許它應該被稱爲半深拷貝。

0

它創建淺副本,因爲但由於Java由值使用參數的所有變量的副本是在克隆對象中可用的但是對於點地址的引用類型的變量副本被創建並以相同的對象是由原始數組稱爲所以當複製對象被修改的原始對象在數組中也得到更新。 請參閱下面的代碼。我不這麼認爲:

import java.util.*; 
import java.lang.*; 
import java.io.*; 

/* Name of the class has to be "Main" only if the class is public. */ 
class ArraysCopyOfDemo 
{ 
    public static void main (String[] args) throws java.lang.Exception 
    { 
     Object[] originalArray= new Object[1]; 
     Employee e1= new Employee("Salman","Khan"); 
     originalArray[0]=e1; 
     System.out.println("Original Array content printed "); 
     printArray(originalArray); 

     Object[] copiedArray=originalArray.clone(); 
     System.out.println("Copied Array content printed "); 
     printArray(copiedArray); 
     System.out.println("Copied Array content modified "); 
     Employee CopiedEmp1= (Employee)copiedArray[0]; 
     CopiedEmp1.setFirstname("Amir"); 
     System.out.println("Copied Array content printed "); 
     printArray(copiedArray); 
     System.out.println("Original Array content printed to verify shallow copy or deep copy"); 
     printArray(originalArray); 
    } 
    private static void printArray(Object[] arrays){ 
     for(Object emp:arrays){ 
      System.out.print(((Employee)emp).getFirstname() + " "); 
      System.out.print(((Employee)emp).getLastname()); 
      System.out.println(); 
     } 
    } 
} 
class Employee implements Cloneable{ 
    private String firstname; 
    private String lastname; 
    public Employee(String firstname,String lastname){ 
     this.firstname=firstname; 
     this.lastname=lastname; 
    } 
    public String getFirstname(){ 
     return firstname; 
    } 
    public String getLastname(){ 
     return lastname; 
    } 
    public void setFirstname(String firstname){ 
     this.firstname=firstname; 
    } 
    public void setLirstname(String lastname){ 
     this.lastname=lastname; 
    } 

} 

O/p 
Original Array content printed 
Salman Khan 
Copied Array content printed 
Salman Khan 
Copied Array content modified 
Copied Array content printed 
Amir Khan 
Original Array content printed to verify shallow copy or deep copy 
Amir Khan 
相關問題