假设您在方法中引用了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