Как клонировать контейнер (например, ArrayList) *легко*? Неправильно ли использовать .clone()?

Мое, возможно, наивное решение для клонирования ArrayList (замена вектора)

ArrayList<Double> alBis = (ArrayList<Double>) alOriginal.clone();

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

Поскольку clone() возвращает объект, я помещаю туда приведение, но затем -Xlint жалуется, что это непроверенное приведение.

И что теперь? Игнорировать это с помощью SupressWarnings? Создайте новый ArrayList и скопируйте исходные элементы с компактным параметром for? Любой библиотечный метод, похожий на Arrays.copyOf()?

Я прочитал предупреждение о непроверенном приведении, но принятый способ невероятно сложен.


person cibercitizen1    schedule 23.02.2011    source источник


Ответы (3)


clone() имеет серьезные недостатки, см. этот вопрос для справки. Не используйте его!

Вместо этого все стандартные коллекции имеют конструкторы копирования. Используй их:

List<Double> original = // some list
List<Double> copy = new ArrayList<Double>(original);

Ссылка:

person Sean Patrick Floyd    schedule 23.02.2011
comment
clone() имеет серьезные недостатки. Можете ли вы уточнить? Я не заметил ничего в ответах на связанный вопрос. - person adamax; 23.02.2011
comment
Прочитайте «Эффективная Java» Джошуа Блоха - person Sean Patrick Floyd; 23.02.2011
comment
При рассмотрении использования клона вместо конструктора копирования необходимо учитывать, что должно произойти, если переданный объект относится к классу, производному от ожидаемого класса. В случае клонирования новый объект будет того же класса, что и исходный; в случае конструктора копирования он будет иметь ожидаемый класс. В некоторых случаях одно поведение будет правильным, а другое явно неправильным, и в разных случаях требуется разное поведение. - person supercat; 23.02.2011
comment
@supercat ерунда. Вы не можете вызвать clone(), не зная, с каким классом вы имеете дело, потому что clone() не поддерживается никаким интерфейсом (Cloneable - это просто интерфейс маркера). Обладая такими же знаниями, вы можете выбрать конструктор копирования нужного класса. - person Sean Patrick Floyd; 23.02.2011
comment
и по той же логике (клон не поддерживается каким-либо интерфейсом) использование clone() также нарушает пункт 52 действующей Java: ссылайтесь на объекты по их интерфейсам - person Sean Patrick Floyd; 23.02.2011
comment
@Sean: если расширяемый класс Foo поддерживает клонирование, а Bar, производный от foo, также поддерживает клонирование, то подпрограмма, принимающая Foo, может попытаться клонировать его, даже если это Bar. Во многих таких случаях новый объект, созданный операцией клонирования, должен быть Bar. Если требуется Foo, чьи Foo-подобные свойства совпадают со свойствами Bar, а специфичные для Bar свойства убраны, может подойти конструктор копирования, но в противном случае я бы предложил, чтобы Clone в 99,44% случаев возвращал объект того же фактического типа, что и оригинал. - person supercat; 23.02.2011
comment
@supercat а) да, так они думали, когда разрабатывали механизм клонирования. Но те же самые люди, теперь говорят нам, что в процессе есть ошибка. б) в контексте вопроса нет иерархии. ArrayList вряд ли когда-либо должен быть подклассом, и его родители не поддерживают clone(). - person Sean Patrick Floyd; 23.02.2011

Неправильно ли использовать .clone()?

Его следует избегать, когда это возможно. Это устаревший, плохо спроектированный и /3410133#3410133">фундаментально неработающий API. Лучше используйте конструктор копирования, как предложил @Sean.

person Péter Török    schedule 23.02.2011

Лично я бы порекомендовал библиотеки Google guava и:

 ImmutableCollection<Double> copy = ImmutableList.copyOf(original);

И не используйте клон JRE, потому что это отстой (если хотите знать почему, то читайте ссылки).

Ссылка:

person Margus    schedule 23.02.2011