2012-02-02 35 views
10

Chỉnh sửa 2: Dưới đây là đoạn mã dựa trên phản hồi của DuffyMo, minh họa cách giải quyết các hạn chế của việc sao chép các mảng đa chiều bằng System.arraycopy.Làm thế nào để sao chép một mảng đa chiều trong java?

import java.util.Arrays; 

public class Randar { 
public static int[][] arrayMaster = {{6,1}, {10,1}, {1,1}}; 
private static int[][] arrayChanges = new int[arrayMaster.length][2]; 

public Randar() { 

} 
public static void main(String[] args) { 
    arrayChanges[0][0] = 0; 
    resetArrays(arrayChanges, arrayMaster); 
    arrayChanges[0][0] = 0; 

    System.out.format("arrayMaster: %s, arrayChanges: %s", Arrays.deepToString(arrayMaster), Arrays.deepToString(arrayChanges)); 
} 


public static void resetArrays(int[][] arrayChanges, int[][] arrayMaster) { 
for (int a=0; a< arrayMaster.length; a++) { 
System.arraycopy(arrayMaster[a], 0, arrayChanges[a], 0, arrayMaster[a].length); 
} 
// arrayChanges = arrayMaster.clone(); will NOT work as expected 
} 
} 

[HỎI ORIGINAL] một cách đơn giản là gì (đầy đủ) sao chép một mảng đa chiều trong java? Chương trình này minh họa vấn đề của tôi.

import java.util.Arrays; 

public class Randar { 
public static int[][] arrayMaster = {{6,1}, {10,1}, {1,1}}; 
static private int[][] arrayChanges = arrayMaster; 

public static void main(String[] args) { 
    arrayChanges[0][0] = 0; 
    resetArrays(); 

    System.out.format("arrayMaster: %s, arrayChanges: %s",Arrays.deepToString(arrayMaster), Arrays.deepToString(arrayChanges)); 
} 


public static void resetArrays() { 
arrayChanges = arrayMaster.clone(); 
} 

} 

Khi mã trên chạy, mảngMaster thay đổi cũng như mảngChuyển đổi, trái với ý định của tôi. Suy nghĩ rằng tôi có thể sao chép từng thành viên mảng chiều duy nhất của arrayMaster, tôi đã cố gắng để có được xung quanh vấn đề với điều này:

for (int iter = 0; iter < arrayMaster.length; iter++) { 
    arrayChanges[iter] = arrayMaster[iter].clone(); 
    } 

nhưng khi tôi chạy mã mà đưa ra một NullPointerException đối với một số lý do. Là viết một phương pháp mà vòng qua các giá trị số nguyên riêng lẻ của các mảng tùy chọn duy nhất của tôi?

Cảm ơn.

CHỈNH SỬA 1: Điều này cũng không khắc phục được sự cố.

import java.util.Arrays; 

public class Randar { 
public int[][] arrayMaster = {{6,1}, {10,1}, {1,1}}; 
private int[][] arrayChanges = arrayMaster.clone(); 

public Randar() { 

} 
public static void main(String[] args) { 
    Randar Randar1 = new Randar(); 
    Randar1.arrayChanges[0][0] = 0; 
    resetArrays(Randar1.arrayChanges, Randar1.arrayMaster); 
    Randar1.arrayChanges[0][0] = 0; 

    System.out.format("arrayMaster: %s, arrayChanges: %s",  Arrays.deepToString(Randar1.arrayMaster), Arrays.deepToString(Randar1.arrayChanges)); 
} 


public static void resetArrays(int[][] arrayChanges, int[][] arrayMaster) { 
/*for (int a=0; a< arrayMaster.length; a++) { 
System.arraycopy(arrayMaster[a].clone(), 0, arrayChanges[a], 0, arrayMaster[a].length); 
} */ 
arrayChanges = arrayMaster.clone(); 
} 
} 

Trả lời

13

Khi mã trên là chạy, arrayMaster thay đổi cũng như arrayChanges, trái với ý định của tôi.

Dòng

static private int[][] arrayChanges = arrayMaster; 

là thủ phạm. Dòng này làm cho arrayChangesarrayMaster trỏ đến cùng một đối tượng, do đó, thay đổi đối với một đối tượng sẽ hiển thị khi bạn truy cập đối tượng từ một trong hai đối tượng đó.

EDIT: Điều gì sẽ xảy ra bất cứ khi nào bạn sao chép một kích thước của một mảng đa chiều

Như Eric Lippert explains, một mảng là khái niệm một danh sách các biến. Nếu bạn chỉ gán một biến khác để trỏ đến cùng một mảng a la static private int[][] arrayChanges = arrayMaster;, thì bạn chưa thay đổi tập hợp các biến. Bạn chưa tạo bất kỳ biến mới nào trừ arrayChanges, vì vậy bạn chưa nhận được nhiều bộ nhớ hơn từ hệ điều hành/JVM, do đó, bất kỳ thay đổi nào bạn thực hiện cho arrayMaster đều được áp dụng cho arrayChanges và ngược lại.

Bây giờ, hãy xem xét mảng hai chiều. Trong Java, một mảng hai chiều là một danh sách các biến xảy ra có thuộc tính mà mỗi một biến này tham chiếu đến một mảng một chiều. Vì vậy, bất cứ khi nào bạn sao chép mảng hai chiều, bạn tạo một danh sách biến mới, mỗi biến trỏ vào cùng một vị trí mà các biến cũ được chỉ ra. Vì vậy, bạn đã đạt được một chút để viết an toàn arrayChanges[0] = new int[10] mà không ảnh hưởng đến arrayMaster, nhưng ngay sau khi bạn bắt đầu tham chiếu arrayChanges[i][j] bạn vẫn đang tham chiếu cùng các mảng cấp hai mà tham chiếu arrayMaster. Những gì bạn thực sự muốn để sâu sao chép một mảng hai chiều kiểu int là

public static int[][] deepCopyIntMatrix(int[][] input) { 
    if (input == null) 
     return null; 
    int[][] result = new int[input.length][]; 
    for (int r = 0; r < input.length; r++) { 
     result[r] = input[r].clone(); 
    } 
    return result; 
} 

Đối với những ai có thể nhìn vào câu trả lời này trong tương lai: yes, nó là tốt hơn thay thế int với T đây và làm cho phương pháp chung chung, nhưng với mục đích này, một phương pháp sao chép sâu hơn cụ thể là đơn giản hơn để giải thích tốt.

+0

Cảm ơn phản hồi của bạn. Tôi viết lại điều này để gộp tất cả các giá trị vào một lớp và không muốn khai báo một cá thể của một đối tượng, do đó, vâng, đó là một vấn đề. Tuy nhiên, vấn đề vẫn tồn tại ngay cả với mã được viết chính xác, như được mô tả ở đây [link] (http://www.crazysquirrel.com/computing/java/basics/multidimensional-array-cloning.jspx) – vancan1ty

+0

Vấn đề không phải là tĩnh ở tất cả. Vấn đề là hai tên 'arrayChanges' và' arrayMaster' tham chiếu đến cùng một đối tượng. Bạn đã tạo một bản sao nông khi bạn khai báo 'mảngChanges'. Xem http://en.wikipedia.org/wiki/Object_copy để biết bản sao nông là gì. –

+0

@ user1184054 Vui lòng đăng mã mới được viết chính xác của bạn cho câu hỏi. –

16

clone thực hiện bản sao "nông". Đó là, mảng ngoài cùng được sao chép, nhưng các giá trị được lưu trữ trong nó không thay đổi. Vì vậy, nếu bạn có A1 = {B1, B2, B3} và sao chép thành A2, nội dung ban đầu của A2 sẽ là {B1, B2, B3}. Nếu bạn thay đổi A1 thành {C1, B2, B3} thì A2 sẽ không thay đổi, nhưng nếu bạn thay đổi nội dung của B1 (không thay thế nó) thì A2 sẽ "thấy" thay đổi đó.

Để thực hiện những gì bạn muốn, bạn phải lặp qua mảng bên ngoài và clone các phần tử của mảng ngoài đó (là mảng bên trong).

Pidgin Java:

int[][] A2 = A1.clone(); 
for (int i = 0; i < A2.length; i++) { 
    A2[i] = A2[i].clone(); 
} 
Các vấn đề liên quan