Философия Java

         

Глубокое копирование при помощи ArrayList


Давайте повторно рассмотрим приведенный ранее в этом приложении пример с ArrayList. Теперь класс Int2 - клонируемый и можно произвести глубокое копирование ArrayList:

//: Приложение А: AddingClone.java

// Для добавления клонирования в ваш класс

// потребуется несколько циклов.

import java.util.*;

class Int2 implements Cloneable { private int i; public Int2(int ii) { i = ii; } public void increment() { i++; } public String toString() { return Integer.toString(i); } public Object clone() { Object o = null; try { o = super.clone(); } catch(CloneNotSupportedException e) { System.err.println("Int2 не может быть клонирован"); } return o; } }

// Поскольку он клонируемый, наследование

// не сделает его не клонируемым:

class Int3 extends Int2 { private int j; // Автоматически дублируется

public Int3(int i) { super(i); } }

public class AddingClone { public static void main(String[] args) { Int2 x = new Int2(10); Int2 x2 = (Int2)x.clone(); x2.increment(); System.out.println( "x = " + x + ", x2 = " + x2); // Все наследники также являются клонируемыми:

Int3 x3 = new Int3(7); x3 = (Int3)x3.clone();

ArrayList v = new ArrayList(); for(int i = 0; i < 10; i++ ) v.add(new Int2(i)); System.out.println("v: " + v); ArrayList v2 = (ArrayList)v.clone(); // Теперь клонируем каждый элемент:

for(int i = 0; i < v.size(); i++) v2.set(i, ((Int2)v2.get(i)).clone()); // Увеличиваемзначения всех элементов v2:

for(Iterator e = v2.iterator(); e.hasNext(); ) ((Int2)e.next()).increment(); // Смотрим, изменились ли значения элементов v:

System.out.println("v: " + v); System.out.println("v2: " + v2); } } ///:~

Int3 наследует Int2 и добавляет новый примитив int j. Вам может показаться что снова потребуется переопределение метода clone() для обеспечения копирования j, но в данном случае это не так. Когда при вызове метода clone() класса Int3 вызывается метод clone() класса Int2, а он в свою очередь вызывает метод Object.clone(), который определяет что работает с классом Int3 и создает побитовый дубликат  класса Int3. Таким образом, до тех пор, пока вы не используете в своем объекте ссылки, которые требуют клонирования, достаточно одного вызова метода Object.clone(), независимо от того насколько этот метод удален от вашего класса по иерархии объектов.

Как видите, для глубокого копирования ArrayList требуется последовательное выполнение операции клонирования для всех объектов, на которые ссылается ArrayList. Нечто подобное требуется и для глубокого клонирования HashMap.

Остальная часть примера нужна в качестве демонстрации успешного клонирования, показывая что изменения, вносимые в клонированные объекты, не отражаются на состоянии исходных объектов.



Содержание раздела