Java: клонировать произвольную коллекцию через ссылку на коллекцию - PullRequest
10 голосов
/ 02 февраля 2011

Предположим, у вас есть ссылка типа java.util.Collection в методе, и вы не можете сказать, на какую реализацию java.util.Collection она будет указывать во время выполнения, возможно ли клонировать коллекцию?

Я хотелреализовать универсальный метод, который будет фильтровать любой тип данной коллекции.Следовательно, метод примет java.util.Collection в качестве ввода.Однако помимо этого я не хотел изменять исходную коллекцию, поэтому я хотел клонировать коллекцию.

Ответы [ 7 ]

9 голосов
/ 02 февраля 2011

К сожалению, коллекция интерфейсов ничего не говорит о реализации Clonable Interface.


Но вы всегда можете скопировать коллекцию:

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

Если вытолько хотите убедиться, что он не изменен, затем оберните его немодифицируемой коллекцией вместо клонирования:

Collection<T> unmodifiable = Collections.unmodifiableCollection(original);
4 голосов
/ 02 февраля 2011

Я собираюсь продемонстрировать в 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, и возвращает статический тип 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();
}
3 голосов
/ 03 февраля 2011

Если вам действительно, действительно, очень, очень нужно это сделать, значит, уродливый хак.

2 голосов
/ 02 февраля 2011

Я вижу три варианта:

  1. Положитесь на собственный метод clone коллекции (предполагая, что он реализует Cloneable), а затем удалите нежелательные элементы. Редактировать: Как указано в комментариях и других ответах, clone() не является общедоступным и, следовательно, недоступным.

  2. Попросить звонящего предоставить пустую коллекциюскопировать целевые элементы между источником и местом назначения.

  3. Определить фабричный интерфейс для создания пустой коллекции и попросить вызывающую программу предоставить фабричную реализацию.Затем скопируйте целевые элементы между источником и местом назначения.

1 голос
/ 02 февраля 2011

Лучше отфильтровать коллекцию, изменив ее в своем методе До звонящего, чтобы предоставить вам оригинальную коллекцию или надлежащую копию.

0 голосов
/ 02 февраля 2011

Если в коллекции реализовано Cloneable, вы можете это сделать.Вам не придется беспокоиться о точном типе;реализация коллекции clone() об этом позаботится.

0 голосов
/ 02 февраля 2011

Теоретически это возможно с помощью отражения, однако не все реализации Collection могут (или должны) быть реализованы таким образом.Ярким примером является результат Collections.singletonList(), у которого вообще нет открытых конструкторов.Другие специальные коллекции также могут вызывать другие проблемы.

Вместо этого я просто проверю интерфейсы, которые реализует входная коллекция, и вернет реализацию "по умолчанию" для этого типа.Так, например:

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

Ответ и так далее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...