2009-08-25 4 views
23

Possible Duplicate:
Java: how to clone ArrayList but also clone its items?Как сделать отдельную копию ArrayList?

У меня есть пример программы, как следующее:

ArrayList<Invoice> orginalInvoice = new ArrayList<Invoice>(); 

//add some items into it here 

ArrayList<Invoice> copiedInvoice = new ArrayList<Invoice>(); 

copiedInvoice.addAll(orginalInvoice); 


Я думал, что я могу изменить элементы внутри copiedInvoice и это не будет влиять на эти элементы внутри originalInoice. Но я был неправ.

Как сделать отдельную копию/клон ArrayList?

Благодаря

+0

Возможный дубликат: http://stackoverflow.com/questions/715650/java-how-to-clone-arraylist-but-also-clone-its-items как упоминается Zed. –

+0

Я закрываю это как дубликат, но его не следует удалять. Не все будут знать, чтобы искать, используя технически правильную терминологию «клон», которую использует оригинал. –

ответ

37

Да, это правильно - Вы должны реализовать clone() (или другой подходящий механизм для копирования вашего объекта, поскольку clone() считается «сломанный» многими программистами). Ваш clone() метод должен выполнить глубокую копию всех изменяемых полей в вашем объекте. Таким образом, модификации клонированного объекта не будут влиять на оригинал.

В вашем примере кода вы создаете второй ArrayList и заполнение его с ссылками на те же объекты, именно поэтому изменения объекта видны с обеих List с. При клонировании подходе ваш код будет выглядеть следующим образом:

List<Foo> originalList = ...; 

// Create new List with same capacity as original (for efficiency). 
List<Foo> copy = new ArrayList<Foo>(originalList.size()); 

for (Foo foo: originalList) { 
    copy.add((Foo)foo.clone()); 
} 

EDIT: Для того, чтобы уточнить, приведенный выше код выполняет глубокую копию оригинального List причем новый List содержит ссылки на копии исходных объектов , Это контрастирует с вызовом ArrayList.clone(), который выполняет shallow copyList. В этом контексте мелкая копия создает новый экземпляр List, но содержит ссылки на исходные объекты.

+3

Почему downvote? – Adamski

+0

Я думаю, что ответ мог бы быть более полезным, если бы вы вступили в различие между клонированием списка и клонированием каждого объекта в списке. Тем не менее, ответ действительно понимает это, даже если он не объясняет это, поэтому +1 компенсировать пониженное голосование. – Yishai

+1

Ошибка: клон имеет «защищенный» доступ в java.lang.object. –

15

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

Однако, если вы храните неизменные объекты, это нормально использовать:

ArrayList copiedInvoice = new ArrayList(originalInvoice);

2

I thought I can modify items inside the copiedInvoice and it will not affect these itmes inside originalInoice.

Это происходит потому, что получает скопирована является ссылочной переменной, а не объект это сам.

Следовательно, вы получаете две «ссылки», указывающие на один и тот же объект.

Если вам нужно скопировать весь объект, вам может понадобиться клонировать его.

Но у вас могут быть проблемы, если вы не клонируете внутренние атрибуты объекта, если они являются другими объектами.

Например, следующее определение класса не даст вам никаких проблем.

public class Something { 
     private int x; 
     private int y; 
     private String stringObject; 
    } 

Если вы создадите копию этого файла, скопируйте текущие значения его атрибутов и все.

Но если у вашего класса есть другой объект внутри, вы можете также его клонировать.

class OtherSomething { 
     Something something; 
     private int x; 
} 

Если вы выполните следующие действия:

Something shared = new Something(); 

OtherSomething one = new OtherSomething(); 

OtherSomething two = new OtherSomething(); 

one.something = shared; 
two.something = shared; 

В этом случае, как один и два имеют одинаковую ссылочную переменную с тем же общим «что-то» и изменение значения в один будет влиять на других ,

Вот почему это намного проще/лучше/проще использовать неизменяемые объекты.

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

+0

Вы заявляете, что у вас не будет проблемы с вашим первым классом: Что-то. Однако Date является объектом и, что более важно, является изменяемым, поэтому его нужно будет скопировать. – Adamski

+0

: P Плохой выбор неизменяемого объекта. У меня была дата для изменяемого объекта. Спасибо, Адамски – OscarRyz

-1

Взгляните на ByteArrayOutputStream и ByteArrayInputStream. Если все ваши классы реализуют Serializable, вы можете сделать копию, используя вышеупомянутые классы.