Подтвердить что ты не робот

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

Возможный дубликат:
Java: как клонировать 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?

Спасибо

4b9b3361

Ответ 1

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

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

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 copy List. В этом контексте мелкая копия создает новый экземпляр List, но содержит ссылки на исходные объекты.

Ответ 2

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

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

ArrayList copiedInvoice = new ArrayList(originalInvoice);

Ответ 3

Я думал, что могу изменять элементы внутри copiedInvoice, и это не повлияет на эти itmes внутри 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;

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

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

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

Ответ 4

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