Глубокое клонирование коллекций в 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);
Это простой способ клонировать объекты, но не если вы ищете производительность.
См. документацию