Java:通过引用Collection来克隆任意Collection

发布于 2024-10-15 19:52:12 字数 220 浏览 3 评论 0原文

假设您在方法中有一个 java.util.Collection 类型的引用,并且无法说明它在运行时将指向 java.util.Collection 的哪个实现,是可以克隆该集合吗?

我想实现一个通用方法,它将过滤给定的任何类型的集合。因此该方法将采用 java.util.Collection 作为输入。然而除此之外,我不想修改原始集合,所以我想克隆该集合。

Suppose you've a reference of type java.util.Collection in a method and cannot say what implementation of java.util.Collection will it point to at run time, is it possible to clone the Collection?

I wanted to implement a generic method which will filter any type of collection given. Hence the method will take java.util.Collection as input. However beyond this, I didn't want to modify the original collection, so I wanted to clone the collection.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

z祗昰~ 2024-10-22 19:52:12

不幸的是,Collection 接口没有提及任何关于实现 Clonable 接口的信息。


但你总是可以做的是复制集合:

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

如果你只想确保它没有被修改,那么用不可修改的集合包装它,而不是克隆它:

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

Unfortunaly the interface Collection does not say anything about implementing Clonable Interface.


But what you can always do is copy the collection:

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

If you only want to make sure that it is not modified then wrap it with an unmodidfiable collection instead of cloning it:

Collection<T> unmodifiable = Collections.unmodifiableCollection(original);
锦爱 2024-10-22 19:52:12

我将在 Scala 中进行演示,因为它有一个可以测试的 REPL,但相同的语义也应该在 Java 中工作。

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

Scala REPL 告诉我 theClone 具有静态类型 Object (您可以将其转换为 Collection[Int]LinkedList[Int]),但是克隆的动态类型仍然是LinkedList

现在我想你想要的是一个方法,当它收到静态类型 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();
}

I'm going to demonstrate in Scala, becuase it has a REPL where I can test, but the same semantics should work in Java.

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

The Scala REPL tells me that theClone has static type Object (you can cast this to Collection[Int] or LinkedList[Int]), but the dynamic type of the clone is still LinkedList.

Now I suppose what you want is a method that returns a static type LinkedList when it recieves a static type LinkedList and returns a static type ArrayList when it recieves a static type ArrayList, etc. in which case

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

In Java, I think that's

<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();
}
半葬歌 2024-10-22 19:52:12

如果你真的真的真的需要这样做,有一个丑陋的黑客。

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

If you really, really, really, really need to do this, there is an ugly hack.

  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;
  }
沧桑㈠ 2024-10-22 19:52:12

我看到三个选项:

  1. 依赖集合自己的clone方法(假设它实现Cloneable),然后删除不需要的元素。 < em>编辑:正如评论和其他答案中所指出的,clone()不是公开的,因此不可访问。

  2. 要求调用者提供一个空集合以在源和目标之间复制目标元素。

  3. 定义一个工厂接口来创建一个空集合并要求调用者提供一个工厂实现。然后在源和目标之间复制目标元素。

I see three options:

  1. Rely on the collection's own clone method (assuming it implements Cloneable) and then remove the undesired elements. Edit: As pointed out in the comments and other answers, clone() is not public and therefore is not accessible.

  2. Ask the caller to provide an empty collection to copy the target elements between source and destination.

  3. Define a factory interface to create an empty collection and ask the caller to provide a factory implementation. Then copy the target elements between source and destination.

草莓酥 2024-10-22 19:52:12

通过在方法中修改集合来更好地过滤集合。由呼叫者向您提供原始集合或其正确副本。

Better filter the collection by modifying it in your method. Up to the caller to provide you with the original collection or a proper copy of it.

極樂鬼 2024-10-22 19:52:12

理论上,可以通过反射来实现,但是并非所有Collection 实现都可以(或应该)以这种方式实例化。一个典型的例子是 Collections.singletonList() 的结果,它根本没有公共构造函数。其他特殊收藏也会引发其他问题。

我要做的只是检查输入集合实现的接口并返回该类型的“默认”实现。例如:

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

Ans等等。

In theory it is possible with reflection, however not all Collection implementations can (or should) be instantiated this way. A prime example is a result of Collections.singletonList(), which has no public constructors at all. Other special collections can raise other issues too.

What I would do instead is to just check the interfaces the input collection implements and return a "default" implementation for that type. So for example:

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

Ans so on.

冷心人i 2024-10-22 19:52:12

如果集合实现了Cloneable,你就可以做到。您不必担心确切的类型;集合的 clone() 实现会处理这个问题。

If the collection implements Cloneable, you can do it. You wouldn't have to worry about the exact type; the collection's clone() implementation would take care of that.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文