2011-02-02 118 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; 
    }