2011-02-02 50 views
10

Giả sử bạn đã tham chiếu loại java.util.Collection trong một phương thức và không thể nói thực hiện java.util.Collection nó sẽ trỏ đến thời gian chạy, có thể sao chép Bộ sưu tập không?Java: sao chép Bộ sưu tập tùy ý thông qua tham chiếu đến Bộ sưu tập

Tôi muốn triển khai phương pháp chung sẽ lọc mọi loại bộ sưu tập được cung cấp. Do đó phương thức sẽ lấy java.util.Collection làm đầu vào. Tuy nhiên ngoài điều này, tôi không muốn sửa đổi bộ sưu tập gốc, vì vậy tôi muốn sao chép bộ sưu tập.

+2

Tại sao bạn cần bộ sưu tập đầu ra của bạn giống loại đầu vào? –

+0

Bộ sưu tập gốc có được giữ nguyên không? – Puce

+0

@Nicolas: Vấn đề tiện lợi :) – Rnet

Trả lời

2

tôi thấy ba tùy chọn:

  1. Dựa vào phương pháp clone riêng của bộ sưu tập (giả sử nó thực hiện Cloneable) và sau đó loại bỏ các yếu tố không mong muốn. Chỉnh sửa: Như đã nêu trong các nhận xét và câu trả lời khác, clone() không công khai và do đó không thể truy cập được.

  2. Yêu cầu người gọi cung cấp bộ sưu tập trống để sao chép các phần tử đích giữa nguồn và đích.

  3. Xác định giao diện nhà máy để tạo bộ sưu tập trống và yêu cầu người gọi cung cấp triển khai nhà máy. Sau đó sao chép các phần tử đích giữa nguồn và đích.

+1

xem nhận xét của tôi về bài viết michael về phương pháp sao chép và giao diện cloneabl. – Nicolas

+1

Có, # 2 là hợp lý hơn – Rnet

0

Về mặt lý thuyết, có thể có sự phản chiếu, tuy nhiên không phải tất cả các triển khai Collection đều có thể (hoặc nên) được khởi tạo theo cách này. Một ví dụ điển hình là kết quả của Collections.singletonList(), mà không có nhà thầu công cộng nào cả. Các bộ sưu tập đặc biệt khác cũng có thể gây ra các vấn đề khác.

Điều tôi sẽ làm thay vào đó là chỉ kiểm tra giao diện mà bộ sưu tập đầu vào triển khai và trả về triển khai "mặc định" cho loại đó. Vì vậy, ví dụ:

Collection c = ... 
if(c instanceof SortedSet) 
    return new TreeSet(c); 
if(c instanceof Set) 
    return new HashSet(c); 

Ans so on.

+2

Ngày mai bất kỳ ai cũng có thể triển khai Bộ sưu tập. –

0

Nếu bộ sưu tập thực hiện Cloneable, bạn có thể thực hiện. Bạn sẽ không phải lo lắng về loại chính xác; việc thực hiện clone() của bộ sưu tập sẽ giải quyết vấn đề đó.

+0

Object.clone() được bảo vệ. Bạn không thể đơn giản gọi nó nếu bạn không biết loại thực của đối tượng. Vâng, có lẽ bạn có thể làm điều đó bằng cách sử dụng phản chiếu như biziclop được đề xuất trong câu trả lời của mình. –

+0

Đã khắc phục sự cố đó - quên bạn cần thực hiện 'cloneable' và ghi đè' clone() '. –

+1

Ngay cả khi bạn thực hiện 'Cloneable', phương thức sao chép có thể không được công khai, hãy xem javadoc http://download.oracle.com/javase/6/docs/api/java/lang/Cloneable.html – Nicolas

9

Không may giao diện Bộ sưu tập không nói bất cứ điều gì về việc triển khai Giao diện Clonable.


Nhưng những gì bạn luôn có thể làm là sao chép bộ sưu tập:

List<T> copy = new ArrayList<T>(original); 

Nếu bạn chỉ muốn chắc chắn rằng nó không được sửa đổi sau đó quấn nó với một bộ sưu tập unmodidfiable thay vì sao chép nó:

Collection<T> unmodifiable = Collections.unmodifiableCollection(original); 
+1

Khá một vài trong số các triển khai của 'Bộ sưu tập', vì vậy phương thức' instanceof' sẽ hoạt động trong nhiều trường hợp. –

+0

Xem nhận xét về các câu trả lời khác: Cloneable không có nghĩa là bạn có thể sử dụng phương pháp sao chép. – Nicolas

+0

Tham chiếu đến bộ sưu tập không thể sửa đổi sẽ vẫn là cục bộ, bộ sưu tập gốc vẫn có thể sửa đổi được bằng các tham chiếu bên ngoài, tôi muốn sửa đổi bản sao của bộ sưu tập gốc và trả lại. – Rnet

4

Tôi sẽ chứng minh trong Scala, bởi vì nó có REPL nơi tôi có thể kiểm tra, nhưng cùng một seman tics sẽ hoạt động trong Java.

import java.util._ 
val orig = new LinkedList[Int] 
val theClone = orig.clone 

Các Scala REPL nói với tôi rằng theClone có tĩnh loại Object (bạn có thể dùng skill này cho Collection[Int] hoặc LinkedList[Int]), nhưng loại năng động của clone vẫn là LinkedList.

Bây giờ tôi cho rằng những gì bạn muốn là một phương thức trả về một loại tĩnh LinkedList khi nó nhận được một loại tĩnh LinkedList và trả về một kiểu tĩnh ArrayList khi nó nhận được một loại tĩnh ArrayList, vv trong trường hợp này

def doClone[C <: Collection[_]](orig:C) = { 
    val cloneMethod = orig.getClass.getDeclaredMethod("clone") 
    if (cloneMethod.isAccessible) 
    cloneMethod.invoke(orig).asInstanceOf[C] 
    else 
    throw new CloneNotSupportedException 
} 

trong Java, tôi nghĩ đó là bộ lọc

<C extends Collection<?> > C doClone (C orig) { 
    java.lang.reflect.Method cloneMethod = 
    orig.getClass().getDeclaredMethod("clone"); 
    if (cloneMethod.isAccessible()) 
    return (C) cloneMethod.invoke(orig); 
    else 
    throw new CloneNotSupportedException(); 
} 
1

Better bộ sưu tập bằng cách sửa đổi nó trong phương pháp của bạn. Người gọi sẽ cung cấp cho bạn bộ sưu tập gốc hoặc bản sao thích hợp của nó.

3

Nếu bạn thực sự, thực sự, thực sự, thực sự cần phải làm điều này, có một hack xấu xí.

public static <T> T tryToClone(T object) 
     throws CloneNotSupportedException { 
    Object clone = null; 

    // Use reflection, because there is no other way 
    try { 
     Method method = object.getClass().getMethod("clone"); 
     clone = method.invoke(object); 
    } catch (InvocationTargetException e) { 
     rethrow(e.getCause()); 
    } catch (Exception cause) { 
     rethrow(cause); 
    } 
    if (object.getClass().isInstance(clone)) { 
     @SuppressWarnings("unchecked") // clone class <= object class <= T 
     T t = (T) clone; 
     return t; 
    } else { 
     throw new ClassCastException(clone.getClass().getName()); 
    } 
    } 

    private static void rethrow(Throwable cause) 
     throws CloneNotSupportedException { 
    if (cause instanceof RuntimeException) { 
     throw (RuntimeException) cause; 
    } 
    if (cause instanceof Error) { 
     throw (Error) cause; 
    } 
    if (cause instanceof CloneNotSupportedException) { 
     throw (CloneNotSupportedException) cause; 
    } 
    CloneNotSupportedException e = new CloneNotSupportedException(); 
    e.initCause(cause); 
    throw e; 
    } 
+3

FYI, điều này xuất phát từ đây: http://code.google.com/p/google-collections/source/browse/trunk/src/com/google/ common/base/Objects.java? spec = svn16 & r = 9 - sau này chúng tôi đã xóa nó, bởi vì nó là một hack hack hack không có ích. –

Các vấn đề liên quan