2008-11-19 40 views
9

Tôi có một số dữ liệu được lưu trữ là ArrayList. Và khi tôi muốn sao lưu dữ liệu này, java giới hạn hai đối tượng mãi mãi. Điều này có nghĩa là khi tôi thay đổi giá trị trong dữ liệu ArrayList, những thay đổi này sẽ được sao lưu. Tôi đã cố gắng sao chép các giá trị từ dữ liệu riêng lẻ sang bản sao lưu trong vòng lặp, cố gắng sử dụng phương thức data.clone() - không có gì hữu ích.Làm thế nào để sao lưu ArrayList trong Java?

+0

Ý anh là gì bởi "dự phòng"? Bạn có nghĩa là bạn muốn tạo một ArrayList khác có chứa những gì trong ArrayList hiện tại? –

Trả lời

12

Tôi nghĩ bạn cần phải .clone() các đối tượng riêng lẻ. Nhân bản ArrayList không phải là "sâu"; nó sẽ chỉ sao chép các tham chiếu đến đối tượng.

-3

Bạn có thể viết một đối tượng kết thúc tốt đẹp hai ArrayLists. Bất cứ điều gì ghi nó để nó thêm, loại bỏ, và sửa đổi dữ liệu trong cả hai cùng một lúc.

1

Có vẻ như (nếu tôi giải thích câu hỏi của bạn một cách chính xác; nó hơi khó) như bạn không sao chép dữ liệu mà bạn đang đề cập đến trong ArrayList vào bản sao lưu của mình; bạn đang sao chép tham chiếu.

Thật khó để nói chính xác cách giải quyết vấn đề của bạn mà không biết loại dữ liệu bạn đang lưu trữ/sao lưu, nhưng chỉ cần chắc chắn rằng bạn đang sao chép các phần tử của dữ liệu chứa trong ArrayList. Điều đó có nghĩa là, trong số những thứ khác, làm những việc như thực hiện một bản sao() trên các phần tử của danh sách, nhưng không phải trên ArrayList (vì nó sẽ tạo một danh sách nhân bản mới với các bản sao của các tham chiếu đến cùng một đối tượng).

4

Tất cả các quy trình này đều tạo bản sao nông. Nếu bạn đang thay đổi các thuộc tính của các đối tượng trong mảng, hai mảng có tham chiếu đến cùng một cá thể.

List org = new java.util.ArrayList(); 
org.add(instance) 
org.get(0).setValue("org val"); 
List copy = new java.util.ArrayList(org); 
org.get(0).setValue("new val"); 

copy.get(0).getValue() sẽ trở lại "new val" cũng vì org.get(0)copy.get(0) trả lại cùng một ví dụ chính xác. Bạn phải thực hiện một bản sao sâu như vậy:

List copy = new java.util.ArrayList(); 
for(Instance obj : org) { 
    copy.add(new Instance(obj)); // call to copy constructor 
} 
+0

Cảm ơn! Tôi đã có cùng một câu hỏi như OP, và bạn đã trả lời nó một cách hoàn hảo. DeepCopy vs bản sao nông! và quan trọng hơn là làm thế nào để thực sự làm một bản sao sâu! –

15

Câu hỏi của bạn không rõ ràng lắm. Nếu bạn sao chép() một ArrayList, bản sao sẽ không bị sửa đổi nếu bạn thay đổi nội dung của bản gốc (nghĩa là nếu bạn thêm hoặc loại bỏ các phần tử), nhưng đó là "bản sao nông", nếu bạn thay đổi các đối tượng thực trong bản gốc cũng được thay đổi trong bản sao.

Nếu bạn muốn tạo "bản sao sâu", để thay đổi đối tượng thực tế sẽ không ảnh hưởng đến bản sao lưu của chúng trong bản sao, thì bạn cần tạo một ArrayList mới và sau đó đi qua bản gốc và mỗi phần tử, sao chép nó vào phần tử mới. Như trong

ArrayList backup = new ArrayList(); 
for (Object obj : data) 
    backup.add(obj.clone()); 
8

Tôi giả định data là tên của ArrayList bạn muốn sao lưu. Nếu vậy, bạn nên biết rằng clone không phải là sâu - nó chỉ tạo bản sao của đối tượng mà trên đó nó được gọi, trong trường hợp này là danh sách. Nếu nó là một bản sao sâu, nó sẽ điền vào danh sách mới với các bản sao của các đối tượng trong đó.

Vì nó không sâu, nếu bạn thay đổi các đối tượng trong danh sách chứa, thì danh sách sao lưu cũng sẽ hiển thị những thay đổi đó, vì nó chứa cùng các đối tượng. Lần duy nhất bạn sẽ không thấy thay đổi trong bản sao lưu sau khi thay đổi danh sách "hiện tại" là khi bạn thêm hoặc xóa các đối tượng khỏi danh sách hiện tại.

Một số lớp học có thể ghi đè lên clone để sâu, nhưng không phải tất cả. Nói chung, nó không phải là một cái gì đó bạn có thể dựa vào. Khi tạo một bản sao lưu của các bộ sưu tập Java, hãy nhớ sao chép các đối tượng được chứa, hoặc chỉ xử lý các bộ sưu tập các đối tượng bất biến.

0

Về vấn đề nhân bản, một khi tôi đã giải quyết vấn đề này bằng cách tuần tự hóa toàn bộ bộ sưu tập thành chuỗi, sau đó tuần tự hóa nó trở lại thành một đối tượng mới. Điều này buộc bạn phải làm cho tất cả các đối tượng của bạn có thể tuần tự hóa và mất khi hai đối tượng thực sự muốn tham chiếu đến một đối tượng thứ ba, nhưng nó có thể là một sự cân bằng khá đơn giản và hữu dụng.

Thực ra, tôi đã không cố gắng này, nhưng bạn có thể có thể sử dụng một ống để serialize trong và ngoài tại thời điểm chính xác tương tự như vậy mà bạn đang không lưu trữ 3 bản trong bộ nhớ (nếu đó là một bộ sưu tập khổng lồ)

-1

Tôi chưa thử nó, nhưng tôi nghĩ Collections.copy sẽ làm điều đó.

[EDIT] Bây giờ, tôi đã cố gắng:

static String GetRandomString(int length) 
{ 
    UUID uuid = UUID.randomUUID(); 
    return uuid.toString().substring(0, length); 
} 

public static void main(String[] args) 
{ 
    ArrayList<String> al = new ArrayList<String>(20); 
    for (int i = 0; i < 10; i++) 
    { 
    al.add(GetRandomString(7)); 
    } 
    ArrayList<String> cloneArray = new ArrayList<String>(al); 
    Collections.copy(cloneArray, al); 
    System.out.println(al); 
    System.out.println(cloneArray); 
    for (int i = 9; i >= 0; i -= 2) 
    { 
    al.remove(i); 
    } 
    System.out.println(al); 
    System.out.println(cloneArray); 
} 
+0

Điều này tôi tin rằng không thực sự hiển thị bản sao sâu kể từ khi thêm/gỡ bỏ hoạt động sẽ không làm thay đổi danh sách ban đầu. Tôi đã thử cùng một mã nhưng thay thế nội dung danh sách bằng một lớp tùy chỉnh và thay đổi nội dung (thay vì xóa chúng), thì danh sách sao chép cũng bị thay đổi. – Nrj

+0

@ Nrj: ah, bạn nói đúng, danh sách là độc lập nhưng vẫn trỏ đến (tham chiếu) cùng một đối tượng, do đó, nó vẫn là một bản sao nông. Của tôi xấu (hey, hai năm trước đây, tôi đã không được rất tốt tại Java! :-)) – PhiLho

3

Phụ thuộc những gì bạn cần. bản sao nông (mục trong danh sách là tài liệu tham khảo để giống như trong bản gốc):

ArrayList backup = new ArrayList(mylist.size()); 
backup.addAll(mylist); 

Sâu bản sao (mục là bản sao cũng):

ArrayList backup = new ArrayList(mylist.size()); 
for(Object o : mylist) { 
    backup.add(o.clone()); 
} 
Các vấn đề liên quan