Java: клонировать произвольный сбор через ссылку на Collection
Предположим, что у вас есть ссылка типа java.util.Collection
в методе и не могу сказать, какую реализацию java.util.Collection
он укажет на время выполнения, можно ли клонировать сборку?
Я хотел реализовать универсальный метод, который будет фильтровать любой тип данных. Следовательно, метод будет принимать java.util.Collection
в качестве входных данных. Однако помимо этого я не хотел изменять оригинальную коллекцию, поэтому я хотел клонировать коллекцию.
Ответы
Ответ 1
Я вижу три варианта:
-
Полагайтесь на собственный метод коллекции clone
(при условии, что он реализует Cloneable
), а затем удаляет нежелательные элементы. Изменить: как указано в комментариях и других ответах, clone()
не является общедоступным и, следовательно, недоступен.
-
Попросите абонента предоставить пустую коллекцию для копирования целевых элементов между источником и получателем.
-
Определите интерфейс factory для создания пустой коллекции и попросите вызывающего пользователя предоставить реализацию factory. Затем скопируйте целевые элементы между источником и получателем.
Ответ 2
К сожалению, интерфейс Collection ничего не говорит о реализации Clonable Interface.
Но то, что вы всегда можете сделать, это скопировать коллекцию:
List<T> copy = new ArrayList<T>(original);
Если вы хотите только убедиться, что он не изменен, тогда оберните его немодифицированной коллекцией, а не клонируйте его:
Collection<T> unmodifiable = Collections.unmodifiableCollection(original);
Ответ 3
Я собираюсь продемонстрировать в 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();
}
Ответ 4
Если вы действительно, действительно, действительно, действительно нужно это сделать, есть уродливый хак.
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;
}
Ответ 5
Улучшите фильтрацию коллекции, изменив ее в вашем методе. До звонящего, чтобы предоставить вам оригинальную коллекцию или соответствующую копию.
Ответ 6
В теории это возможно с отражением, однако не все Collection
реализации могут (или должны) быть созданы таким образом. Первым примером является результат Collections.singletonList()
, который вообще не имеет общих конструкторов. Другие специальные коллекции могут также поднимать и другие проблемы.
Вместо этого я хотел бы просто проверить интерфейсы, которые реализует входная коллекция, и вернуть реализацию по умолчанию для этого типа. Так, например:
Collection c = ...
if( c instanceof SortedSet )
return new TreeSet( c );
if( c instanceof Set )
return new HashSet( c );
Ans и так далее.
Ответ 7
Если коллекция реализует Cloneable
, вы можете это сделать. Вам не нужно беспокоиться о точном типе; реализация коллекции clone()
позаботится об этом.