Как сделать выделенную копию 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
?
Спасибо
Ответы
Ответ 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, вы можете сделать копию, используя вышеупомянутые классы.