Глубокое клонирование коллекций в java

Недавно я столкнулся с этим вопросом в интервью:

Напишите функцию для возврата экземпляра глубокого клонирования класса Рисование

public class Drawing{

  public List<Shape> shapes=new LinkedList<Shape>();

}

где shape - абстрактный класс, имеющий много конкретных реализаций

public abstract class Shape implements Serializable{

}

Кто-нибудь может рассказать, как подойти к этому? Нужно ли добавлять метод clone во все конкретные реализации?

Ответ 1

Что вам нужно сделать, это сначала сериализовать List<Shape>, а затем десериализовать и вернуть новый экземпляр Drawing с десериализованным List

public static Drawing deepClone(Drawing drawing) {
    try {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(drawing.shapes); //Serializes the drawing.shapes

        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bais); 
        return new Drawing((LinkedList<Shape>)ois.readObject()); //Deserializing and reading 
    } catch (IOException e) {
        return null;
    } catch (ClassNotFoundException e) {
        return null;
    }
}

Предполагая, что у вас есть конструктор в Drawing, который принимает параметр LinkedList<Shape> как

ИЗМЕНИТЬ

Вам не нужно добавлять clone() в класс Shape при переопределении метода clone() при реализации интерфейса Cloneable, но в соответствии с этим вопросом они хотят, чтобы вы создавали клоны с использованием интерфейса Serializable.

Ответ 2

Каждый подкласс класса Shape знает, как создать глубокую копию самого себя, потому что это одна вещь, которую должны выполнять реализации Serializable. Таким образом, переместите список в Drawing и сериализуйте/десериализуйте объект Shape, чтобы создать свою глубокую копию каждого Shape в списке.

Ответ 3

Вы также можете использовать библиотеку, которая быстрее, чем методы сериализации.

Cloner cloner=new Cloner();

MyClass clone=cloner.deepClone(o);
// clone is a deep-clone of o

Ответ 4

Я бы предложил использовать SerializationUtils.clone из Apach Commons Lang

Этот метод предназначен для глубокого клонирования:

SomeObject cloned = org.apache.commons.lang.SerializationUtils.clone(someObject);

Это простой способ клонировать объекты, но не если вы ищете производительность.

См. документацию