2011-02-02 102 views
10

假設您在方法中引用了java.util.Collection類型,並且無法說明它在運行時指向的實現是java.util.Collection,是否可以克隆集合?Java:通過引用收集集合的任意集合

我想實現一個通用的方法,它將過濾任何類型的集合。因此該方法將以java.util.Collection作爲輸入。但是除此之外,我不想修改原始集合,所以我想克隆集合。

+2

爲什麼你需要你的輸出集合與輸入集合類型相同? – 2011-02-02 14:25:33

+0

原始集合應該保持不變嗎? – Puce 2011-02-02 14:30:14

+0

@Nicolas:方便的事情:) – Rnet 2011-02-02 14:33:11

回答

2

我看到三個選項:

  1. 依靠收集自己的 clone方法(假設它實現 Cloneable),然後刪除不需要的元素。 編輯:正如在評論和其他答案中指出的,clone()不公開,因此無法訪問。

  2. 請求調用者提供一個空集合來複制源和目標之間的目標元素。

  3. 定義一個工廠接口來創建一個空集合並要求調用者提供工廠實現。然後複製源和目標之間的目標元素。

0

理論上可以反射,但不是所有的實現都可以(或應該)以這種方式實例化。一個主要的例子是Collections.singletonList()的結果,它根本沒有公共構造函數。其他特殊館藏也可能引發其他問題。

我會做的只是檢查輸入集合實現的接口並返回該類型的「默認」實現。例如:

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

Ans等。

+2

明天任何人都可以實現Collection。 – 2011-02-02 14:28:45

0

如果收集實施Cloneable,您可以這樣做。你不必擔心確切的類型;該集合的clone()實現將照顧到這一點。

+0

Object.clone()受保護。如果您不知道對象的真實類型,則不能簡單地調用它。那麼,也許你可以用biziclop在他的回答中提出的反思來做到這一點。 – 2011-02-02 14:31:32

+0

解決了這個問題 - 忘記了你需要實現`cloneable`並重寫`clone()`。 – 2011-02-02 14:33:16

9

不幸的是,接口Collection並沒有提到任何有關實現Clonable Interface的內容。


但你總是可以做的就是複製集:

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

如果你只是想確保它不被修改然後用unmodidfiable集合,而不是克隆它包它:

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

我要去斯卡拉證明,原因是其擁有一個REPL在那裏我可以測試,但同樣的塞曼抽搐應該在Java中工作。

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

斯卡拉REPL告訴我,theClone具有靜態類型Object(你可以施放這Collection[Int]LinkedList[Int]),但動態類型的克隆仍然是LinkedList

現在,我想你想要的是一個返回靜態類型LinkedList的方法時,臨危靜態類型LinkedList並返回一個靜態類型ArrayList時臨危靜態類型ArrayList等在這種情況下

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

在Java中,我認爲這是

<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

更好的過濾器收集在你的方法修改它。直到呼叫者爲您提供原始集合或其正確的副本。

3

如果你確實真的需要這樣做,那就是一件醜惡的事情。

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; 
    }