Как выполнить глубокое копирование объекта в Java?

«Как выполнить глубокое копирование объекта в Java?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Глубокое копирование создает новый объект и рекурсивно копирует все поля, включая вложенные объекты, а не просто копирует ссылки на них.

Основные подходы:

  1. Ручная реализация (через конструктор копирования или clone()):

    public class Person {
        private String name;
        private Address address; // mutable объект
    
        // Конструктор глубокого копирования
        public Person(Person original) {
            this.name = original.name;
            this.address = new Address(original.address); // Копируем вложенный объект
        }
    
        // Или через переопределение clone() (менее предпочтительно)
        @Override
        protected Person clone() throws CloneNotSupportedException {
            Person cloned = (Person) super.clone();
            cloned.address = this.address.clone(); // Требует, чтобы Address тоже реализовывал Cloneable
            return cloned;
        }
    }
  2. Сериализация/десериализация:

    import java.io.*;
    
    public static <T extends Serializable> T deepCopy(T object) throws IOException, ClassNotFoundException {
        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(byteOut);
        out.writeObject(object);
        out.flush();
    
        ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
        ObjectInputStream in = new ObjectInputStream(byteIn);
        return (T) in.readObject();
    }
    • Плюсы: Универсально для любых графов объектов.
    • Минусы: Низкая производительность; все объекты в графе должны реализовывать Serializable.
  3. Использование библиотек (рекомендуется для сложных объектов):

    • Apache Commons Lang: SerializationUtils.clone(object) (требует Serializable).
    • Jackson/Gson: Сериализация в JSON и обратная десериализация.
      // Пример с Gson
      Gson gson = new Gson();
      Person copy = gson.fromJson(gson.toJson(original), Person.class);

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