2008-09-10 23 views
129

Tôi có một số ArrayList<String> mà tôi muốn trả lại một bản sao. ArrayList có một phương pháp nhân bản có chữ ký sau đây:Làm cách nào để sao chép Danh sách chung trong Java?

public Object clone() 

Sau khi tôi gọi phương pháp này, làm thế nào để cast Object trở lại ArrayList<String>?

+14

Không, đây là một câu hỏi hợp lệ. Java không hỗ trợ Generics "đúng", với xóa thời gian chạy kiểu và tất cả, do đó, các loại chi tiết có thể được khôn lanh. Hơn nữa, giao diện Cloneable và cơ chế phương thức Object.clone() tương tự khó hiểu. –

+0

OK, tôi chủ yếu làm C# nơi điều này thực sự dễ dàng. Vui lòng cho tôi biết nếu bạn muốn tôi xóa nhận xét khỏi câu hỏi này. – Espo

+1

Bạn có thể để lại nhận xét. Tôi nghĩ rằng các chỉnh sửa của tôi đã giải thích những gì tôi gặp phải. –

Trả lời

50
ArrayList newArrayList = (ArrayList) oldArrayList.clone(); 
+35

Điều này sẽ làm việc tốt cho Strings (đó là câu hỏi được yêu cầu), nhưng đáng chú ý là ArrayList.clone sẽ thực hiện một bản sao nông, vì vậy nếu có các đối tượng có thể thay đổi trong danh sách, chúng sẽ không được nhân bản (và thay đổi một trong một danh sách sẽ thay đổi một trong những danh sách khác là tốt – pkaeding

+43

Bạn nên tránh sử dụng các loại thô trong bất cứ điều gì nhưng mã di sản.Bạn nên sử dụng 'ArrayList newArrayList = (ArrayList ) oldArrayList.clone();' – cdmckay

+18

Nó quá xấu ArrayList có một phương pháp #clone, nhưng danh sách chính nó không.Sigh – rogerdpack

1
ArrayList first = new ArrayList(); 
ArrayList copy = (ArrayList) first.clone(); 
5

Tôi tìm thấy bằng addAll hoạt động tốt.

ArrayList(String) copy = new ArrayList(String)(); 
copy.addAll(original); 

ngoặc được sử dụng chứ không phải là thuốc generic cú pháp

+4

Điều đó sẽ hoạt động đối với Strings, nhưng không hoạt động đối với các đối tượng có thể thay đổi. Bạn cũng sẽ muốn sao chép chúng. – jodonnell

+0

Vâng, câu hỏi của anh ta là dành cho dây. Và anh ta có vấn đề về generics mà không thực sự thích những thứ đúc trong trường hợp này. –

+0

Ngoài ra, ArrayList.clone sẽ chỉ làm một bản sao nông, vì vậy các đối tượng có thể thay đổi trong danh sách sẽ không được nhân bản bằng cách sử dụng phương thức đó. – pkaeding

2

này cũng nên làm việc:

ArrayList<String> orig = new ArrayList<String>(); 
ArrayList<String> copy = (ArrayList<String>) orig.clone() 
+1

Điều này sẽ không hoạt động vì Danh sách không có phương thức sao chép. –

+0

Thật vậy.Tôi vừa cập nhật nó để sửa lỗi này. – pkaeding

+9

Vâng, bây giờ bình luận của tôi có vẻ ngu ngốc. :) –

14

Tôi nghĩ rằng điều này sẽ làm các trick sử dụng API Collections:

Note : phương thức sao chép chạy trong thời gian tuyến tính.

//assume oldList exists and has data in it. 
List<String> newList = new ArrayList<String>(); 
Collections.copy(newList, oldList); 
+13

Tại sao không chỉ sử dụng ArrayList mới (oldList)? – cdmckay

+3

Tôi tin rằng điều này sẽ không hoạt động, từ doc * Danh sách đích phải ít nhất là danh sách nguồn. Nếu nó dài hơn, các phần tử còn lại trong danh sách đích sẽ không bị ảnh hưởng. –

+0

@GregDomjan không phải là tôi đồng ý rằng đây là cách tốt nhất, nhưng đó là một cách để làm điều đó. Để giải quyết vấn đề của bạn, nó giống như thế này: Danh sách newList = new ArrayList <> (oldList.size()); – nckbrz

276

Tại sao bạn muốn sao chép? Tạo danh sách mới thường có ý nghĩa hơn.

List<String> strs; 
... 
List<String> newStrs = new ArrayList<>(strs); 

Hoàn thành công việc.

+16

Bạn có thể không biết loại danh sách đó là gì. Nó có thể là một LinkedList, MyOwnCustomList hoặc một lớp con của ArrayList, trong trường hợp mới tạo một ArrayList sẽ là kiểu không chính xác. –

+48

Tôi có quan tâm đến việc triển khai danh sách ban đầu nào được sử dụng không? Tôi có thể quan tâm đến việc triển khai danh sách mới nào. –

+12

@Steve Kuo: Chữ ký là 'ArrayList (Bộ sưu tập c) 'có nghĩa là nó không quan trọng đối với loại danh sách bạn sử dụng làm đối số. – cdmckay

16

Lưu ý rằng Object.clone() có một số vấn đề lớn và việc sử dụng nó không được khuyến khích trong hầu hết các trường hợp. Vui lòng xem mục 11, từ "Effective Java" của Joshua Bloch để có câu trả lời hoàn chỉnh. Tôi tin rằng bạn có thể sử dụng một cách an toàn Object.clone() trên các mảng kiểu nguyên thủy, nhưng ngoài ra bạn cần phải thận trọng về việc sử dụng đúng và ghi đè bản sao. Bạn có lẽ là tốt hơn off xác định một constructor sao chép hoặc một phương pháp nhà máy tĩnh rõ ràng nhân bản các đối tượng theo ngữ nghĩa của bạn.

2

Hãy rất cẩn thận khi nhân bản ArrayLists. Nhân bản trong java là nông cạn. Điều này có nghĩa là nó sẽ chỉ sao chép chính Arraylist chứ không phải các thành viên của nó. Vì vậy, nếu bạn có một ArrayList X1 và sao chép nó vào X2, bất kỳ thay đổi nào trong X2 cũng sẽ hiển thị trong X1 và ngược lại. Khi bạn sao chép, bạn sẽ chỉ tạo ra một ArrayList mới với các con trỏ đến cùng các phần tử trong bản gốc.

0

Tôi không phải là một chuyên gia java, nhưng tôi có cùng một vấn đề và tôi đã cố gắng giải quyết bằng phương pháp này. (Nó cho rằng T có một hàm tạo bản sao).

public static <T extends Object> List<T> clone(List<T> list) { 
     try { 
      List<T> c = list.getClass().newInstance(); 
      for(T t: list) { 
      T copy = (T) t.getClass().getDeclaredConstructor(t.getclass()).newInstance(t); 
      c.add(copy); 
      } 
      return c; 
     } catch(Exception e) { 
      throw new RuntimeException("List cloning unsupported",e); 
     } 
} 
20

Đây là mã tôi sử dụng cho rằng:

ArrayList copy = new ArrayList (original.size()); 
Collections.copy(copy, original); 

Hy vọng là hữu ích cho bạn

+1

Và tránh sử dụng các loại thô .. vì vậy thay vì 'ArrayList' sử dụng' ArrayList ' – milosmns

+1

http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#copy-java. util.List-java.util.List- Không hoạt động vì kích thước danh sách khác nhau. –

2

chức năng của tôi để sao chép một danh sách với kiểu:

public static <T extends Object> List<T> cloneList(List<T> list) { 
    return ((List<T>) ((ArrayList<T>) list).clone()); 
} 
+0

Bạn đưa một danh sách không xác định vào ArrayList, nó sẽ không hoạt động nếu nó không phải là một. –

2

Để bản sao một giao diện chung như java.util.List bạn sẽ chỉ cần truyền nó.ở đây bạn là một ví dụ:

List list = new ArrayList(); 
List list2 = ((List) ((ArrayList) list).clone()); 

Nó là một chút khó khăn, nhưng nó hoạt động, nếu bạn được giới hạn để trả về một giao diện List, vì vậy bất cứ ai sau khi bạn có thể thực hiện danh sách của bạn bất cứ khi nào ông muốn.

Tôi biết câu trả lời này là gần với câu trả lời cuối cùng, nhưng câu trả lời của tôi trả lời thế nào để làm tất cả điều đó trong khi bạn đang làm việc với List -the huynh generic không ArrayList

+1

bạn đang giả định rằng nó sẽ luôn luôn là một ArrayList đó là không đúng –

+0

@JuanCarlosDiaz sẽ, đây là câu hỏi, đó là về ArrayList, vì vậy tôi đã trả lời nó cho ArrayList :) –

12

Với Java 8 nó có thể được nhân bản với một dòng suối.

import static java.util.stream.Collectors.toList; 

...

List<AnObject> clone = myList.stream().collect(toList()); 
4

Nếu bạn muốn điều này để có thể trở lại danh sách trong một getter nó sẽ là tốt hơn để làm:

ImmutableList.copyOf(list); 
Các vấn đề liên quan