Как да клонирате контейнер (напр. ArrayList) *лесно*? Грешно ли е да се използва .clone()?

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

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

като се има предвид, че тъй като масивът съдържа неизменни Doubles, не е необходимо да клонирам тях, а само контейнера.

Тъй като clone() връща обект, поставям там каста, но след това -Xlint се оплаква, че е непроверен каст.

И сега какво? Игнориране с supressWarnings? Създайте нов ArrayList и копирайте оригиналните елементи с компактен за? Всеки библиотечен метод, подобен на 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() също нарушава Ефективна позиция на Java 52: Обръщайте се към обекти чрез техните интерфейси - person Sean Patrick Floyd; 23.02.2011
comment
@Sean: Ако разширяем клас Foo поддържа клониране и Bar, който произлиза от foo, също поддържа клониране, тогава рутина, която приема Foo, може да се опита да го клонира, дори ако е Bar. В много такива случаи новият обект, произведен от операцията по клониране, трябва да бъде лента. Ако това, което е необходимо, е Foo, чиито Foo-ish свойства съответстват на тези на лентата и чиито специфични за лентата свойства са премахнати, конструкторът за копиране може да е подходящ, но в противен случай бих предложил Clone в 99,44% от случаите да върне обект от същия действителен тип като оригинала. - person supercat; 23.02.2011
comment
@supercat a) да, това са мислили, когато са проектирали механизма за клониране. Но същите хора сега ни казват, че има недостатък в процеса. б) в контекста на въпроса няма йерархия. ArrayList почти никога не трябва да бъде подкласиран и родителите му не поддържат clone(). - person Sean Patrick Floyd; 23.02.2011

Грешно ли е да се използва .clone()?

Трябва да се избягва, когато е възможно. Това е остарял, лошо проектиран и фундаментално повреден API. По-добре използвайте конструктора за копиране, както предложи @Sean.

person Péter Török    schedule 23.02.2011

Лично аз бих препоръчал Google guava-libraries и:

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

И не използвайте JRE клонинг, защото е гадно (ако искате да знаете защо, прочетете препратките).

Справка:

person Margus    schedule 23.02.2011