2013-08-21 26 views
15

Dường như có rất nhiều sự nhầm lẫn và ý kiến ​​khác nhau về điều này ([1] và các nguồn khác) về việc liệu Arrays.copyOf sẽ tạo bản sao sâu hay nông.Arrays.copyOf có tạo bản sao nông hoặc sâu không?

thử nghiệm này cho thấy rằng các bản sao là sâu:

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

sourceArray[0] = "Bar"; 

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

thử nghiệm này cho thấy rằng các bản sao là nông cạn:

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 

Là giải pháp đơn giản là một bản sao sâu sắc về các khía cạnh cấp cao nhất được tạo ra, nhưng các kích thước khác là bản sao nông? Sự thật là gì?

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

+0

Có lẽ chỉ là một sự xuất hiện khác của việc thực hiện chuỗi – Matthias

+0

@Matthias: Tôi không nghĩ vậy. Vì "Foo" là một chữ, nó sẽ được thực tập; các thử nghiệm giả định rằng. Nếu giả định đó là chính xác, thì các thử nghiệm đang điều tra xem phần tử đích có bị thay đổi bởi '=" Bar "' của phần tử nguồn tương ứng hay không. – ToolmakerSteve

+0

Tôi không thấy nơi các bài kiểm tra đưa ra bất kỳ giả định nào về việc liệu Chuỗi có được nội bộ hóa hay không.Tôi không thấy bất kỳ bài kiểm tra nhận dạng nào, tôi chỉ thấy các bài kiểm tra bình đẳng. Các kết quả sẽ giống hệt nhau đối với các bản sao nông và sâu, vì các xét nghiệm bình đẳng không thể khác nhau giữa các bản sao nông và sâu. Một trong những nhu cầu kiểm tra nhận dạng để khác nhau giữa các bản sao nông và sâu. –

Trả lời

22

Nó tạo ra một bản sao cạn, tức là mới mảng chứa tài liệu tham khảo "cũ" (cho các đối tượng tương tự, những người không bị sao chép).

Cụ thể, nếu bạn có mảng lồng nhau, các mảng đó sẽ không được sao chép. Bạn sẽ chỉ nhận được một mảng mới có các điểm "cấp cao nhất" tới cùng một mảng "cấp thứ hai" như bản gốc đã làm. Mọi thay đổi bên trong các mảng lồng nhau đó sẽ được phản ánh trong cả bản sao và bản gốc.

thử nghiệm này cho thấy rằng các bản sao là sâu:

Không, nó không. Khi bạn gán một đối tượng mới cho mảng "ban đầu", điều này không ảnh hưởng đến bản sao. Đó là, sau khi tất cả, một bản sao.

Đây là tình huống tương tự như:

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

assertEquals(y, "foo"); 

Không "bản sao sâu" ở đây.

4

Mẫu Java Doc

.... hai mảng sẽ chứa các giá trị giống hệt nhau.

Vì vậy, trong trường hợp mảng chứa tham chiếu, chỉ tham chiếu được sao chép chứ không phải đối tượng thực tế. Có nghĩa là một bản sao nông.

-4

Đây là bản sao sâu. Nó xuất hiện nông trong trường hợp của Strings bởi vì dưới bìa, Strings là Singletons. JVM có một bộ nhớ cho các chuỗi và chỉ tạo một bản sao của mỗi chuỗi duy nhất. Vì vậy, bạn luôn nhận được một bản sao của tham chiếu đến chuỗi đó. Ví dụ dưới đây cho thấy rằng một bản sao sâu được tạo cho đối tượng lớp. Khi mảng ban đầu được thay đổi, bản sao không thay đổi.

public class 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

Nó không phải là một bản sao sâu, một bản sao sâu sẽ đòi hỏi phải làm bản sao của tất cả các đối tượng được lưu trữ trong mảng mình. Arrays.copyOf không làm điều đó; nó chỉ đơn giản là tạo bản sao của các tham chiếu - tức là bản sao nông –

+0

Ngoài ra, đối số cho lý do tại sao một chuỗi các chuỗi sẽ hoạt động khác với các đối tượng khác chỉ đơn giản là sai. Có, chuỗi ký tự được tập trung. Không, điều đó không dẫn đến chuỗi hoạt động khác với bất kỳ đối tượng nào khác (tham chiếu). Có thể người trả lời này đã bị lừa bởi sự phụ thuộc của mã câu hỏi về chuỗi ký tự của các chữ, đó là điều cần thiết cho bài kiểm tra đầu tiên để vượt qua. Câu hỏi sẽ rõ ràng hơn nếu nó đã đặt '" Foo "' vào một biến, và sau đó sử dụng biến đó ở khắp mọi nơi. – ToolmakerSteve

+0

Rất tiếc, câu trả lời của bạn sai theo nhiều cách. Bản sao là một bản sao nông. Các chuỗi không được luôn luôn được sắp xếp, chỉ trong các trường hợp đặc biệt. Ví dụ, trong 'String foo =" Foo "; Chuỗi foo2 = new String (foo); ',' foo2' là một bản sao mới. Và không thể kết luận từ một phương thức 'Object.equals()' bị ghi đè cho dù một bản sao sâu hay nông, bởi vì đó là một cái gì đó mà 'Object.equals()' ẩn trong mỗi định nghĩa. –

1

'nông' hay 'sâu' - và đây là một vấn đề mà tôi thấy không có một định nghĩa chính xác - phương pháp Arrays.copyOf(..) DOES trong thực tế sản xuất một bản sao của mảng nguồn không bị ảnh hưởng bởi các thay đổi đối với mảng nguồn.

Lấy ví dụ đơn giản sau đây với int mảng:

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] 

Trong thực tế, khi mọi người tìm kiếm một "bản sao sâu" của một mảng, họ chỉ muốn một cái gì đó mà không bị ảnh hưởng bởi những thay đổi với bản gốc.

Và phương thức Arrays.copyOf (..) `này cung cấp cho chúng điều này.

Cũng như mảng kiểu nguyên thủy, mảng đối tượng String cũng cư xử như ví dụ trên, cho sản lượng như:

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] 

khi các mục mảng nguồn ban đầu được nối bằng "1".

Nó cũng 'hoạt động' cho mảng Đối tượng theo nghĩa là mục tiêu không còn gắn với nguồn khi mục tiêu được gán lại. NHƯNG nhìn vào đầu ra cho các yếu tố đầu tiên của cả hai mảng sau khi sao chép và sau đó sau khi thay đổi nguồn [0] tiết lộ sự thật đầy đủ:

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

Sau khi mảng nguồn gốc được sao chép, các yếu tố mục tiêu chỉ đơn giản là đã được chỉ với bất kỳ giá trị nào hiện đang được giữ trong các đối tác nguồn của chúng. Đối với mục tiêu [0] nó là nội dung của địa chỉ bộ nhớ 1db9742 - cũng là cùng một địa chỉ bộ nhớ giữ nguồn [0]. . . .

Và lý do chúng tôi có được một debonding giữa nguồn và đích sau khi nguồn [0] được bố trí là do thực tế rằng tuyên bố nhiệm vụ

source[0] = new Object(); 

chỉ đơn giản là làm cho tài liệu tham khảo bộ nhớ được tổ chức tại nguồn [0] để được thay đổi thành một số vị trí mới như một đối tượng mới đang được chỉ ra. Vì vậy, nó không phải là sau khi tất cả một bản sao sâu thật sự trong ý nghĩa tinh khiết, mặc dù trong nhiều trường hợp nó mang lại cho coder những lợi ích tương tự như một bản sao sâu.

Với mảng dữ liệu nguyên thủy, phương thức Arrays.copyOf (..) không thể sao chép tham chiếu vì chúng không được sử dụng cho nguyên thủy. Nó chỉ sao chép các giá trị phần tử nguồn vào các phần tử đích. Một lần nữa chúng ta có tác dụng tương tự như một bản sao sâu tại các chi phí của một hoạt động cần mã ít hơn nhiều so với một bản sao sâu.

Vì vậy, Arrays.copyOf (..) là bản sao sâu 'rẻ' cho cả mảng nguyên thủy và đối tượng 1-D. Nhưng bất kỳ mảng dữ liệu phức tạp hơn và nó được phát hiện ra.

Có thể nó nên được gọi là bản sao bán sâu.

0

Nó tạo ra bản sao Nông vì vì java sử dụng tham số theo giá trị, bản sao của tất cả biến có sẵn trong đối tượng nhân bản, tuy nhiên đối với bản sao biến kiểu địa chỉ tham chiếu được tạo và trỏ đến cùng một đối tượng được gọi bởi mảng ban đầu. đối tượng đã sao chép được sửa đổi đối tượng gốc trong mảng cũng được cập nhật. xem mã bên dưới.

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 
Các vấn đề liên quan