假設您在方法中引用了java.util.Collection
類型,並且無法說明它在運行時指向的實現是java.util.Collection
,是否可以克隆集合?Java:通過引用收集集合的任意集合
我想實現一個通用的方法,它將過濾任何類型的集合。因此該方法將以java.util.Collection
作爲輸入。但是除此之外,我不想修改原始集合,所以我想克隆集合。
假設您在方法中引用了java.util.Collection
類型,並且無法說明它在運行時指向的實現是java.util.Collection
,是否可以克隆集合?Java:通過引用收集集合的任意集合
我想實現一個通用的方法,它將過濾任何類型的集合。因此該方法將以java.util.Collection
作爲輸入。但是除此之外,我不想修改原始集合,所以我想克隆集合。
我看到三個選項:
依靠收集自己的
編輯:正如在評論和其他答案中指出的,clone
方法(假設它實現
Cloneable
),然後刪除不需要的元素。
clone()
不公開,因此無法訪問。
請求調用者提供一個空集合來複制源和目標之間的目標元素。
定義一個工廠接口來創建一個空集合並要求調用者提供工廠實現。然後複製源和目標之間的目標元素。
理論上可以反射,但不是所有的實現都可以(或應該)以這種方式實例化。一個主要的例子是Collections.singletonList()
的結果,它根本沒有公共構造函數。其他特殊館藏也可能引發其他問題。
我會做的只是檢查輸入集合實現的接口並返回該類型的「默認」實現。例如:
Collection c = ...
if(c instanceof SortedSet)
return new TreeSet(c);
if(c instanceof Set)
return new HashSet(c);
Ans等。
明天任何人都可以實現Collection。 – 2011-02-02 14:28:45
如果收集實施Cloneable
,您可以這樣做。你不必擔心確切的類型;該集合的clone()
實現將照顧到這一點。
Object.clone()受保護。如果您不知道對象的真實類型,則不能簡單地調用它。那麼,也許你可以用biziclop在他的回答中提出的反思來做到這一點。 – 2011-02-02 14:31:32
解決了這個問題 - 忘記了你需要實現`cloneable`並重寫`clone()`。 – 2011-02-02 14:33:16
不幸的是,接口Collection並沒有提到任何有關實現Clonable Interface的內容。
但你總是可以做的就是複製集:
List<T> copy = new ArrayList<T>(original);
如果你只是想確保它不被修改然後用unmodidfiable集合,而不是克隆它包它:
Collection<T> unmodifiable = Collections.unmodifiableCollection(original);
我要去斯卡拉證明,原因是其擁有一個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();
}
更好的過濾器收集在你的方法修改它。直到呼叫者爲您提供原始集合或其正確的副本。
如果你確實真的需要這樣做,那就是一件醜惡的事情。
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;
}
爲什麼你需要你的輸出集合與輸入集合類型相同? – 2011-02-02 14:25:33
原始集合應該保持不變嗎? – Puce 2011-02-02 14:30:14
@Nicolas:方便的事情:) – Rnet 2011-02-02 14:33:11