← Назад к вопросам

Как скопировать объект в Java

2.0 Middle🔥 151 комментариев
#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Способы копирования объектов в Java

Копирование объектов — важная задача при работе с данными. В Java существуют несколько способов создания копии объекта, каждый с определёнными преимуществами и недостатками.

Способ 1: Поверхностное копирование (Shallow Copy)

Этот способ копирует только значения полей объекта, но не копирует вложенные объекты:

public class User {
    private String name;
    private int age;
    private Address address;  // Вложенный объект
    
    // Конструктор копирования
    public User(User original) {
        this.name = original.name;
        this.age = original.age;
        this.address = original.address;  // Ссылка на тот же объект!
    }
}

public class Address {
    private String street;
    private String city;
    
    public Address(String street, String city) {
        this.street = street;
        this.city = city;
    }
}

// Использование
User user1 = new User("John", 30, new Address("123 Main St", "NYC"));
User user2 = new User(user1);
user2.getAddress().setCity("LA");  // Изменит также address в user1!

Способ 2: Глубокое копирование (Deep Copy) через конструктор

Этот способ копирует объект полностью, включая все вложенные объекты:

public class User {
    private String name;
    private int age;
    private Address address;
    
    // Конструктор копирования с глубоким копированием
    public User(User original) {
        this.name = original.name;
        this.age = original.age;
        // Создаём новый объект Address
        this.address = new Address(original.address);
    }
}

public class Address {
    private String street;
    private String city;
    
    public Address(String street, String city) {
        this.street = street;
        this.city = city;
    }
    
    // Конструктор копирования для Address
    public Address(Address original) {
        this.street = original.street;
        this.city = original.city;
    }
}

// Использование
User user1 = new User("John", 30, new Address("123 Main St", "NYC"));
User user2 = new User(user1);
user2.getAddress().setCity("LA");  // Изменит только address в user2

Способ 3: Использование Cloneable интерфейса

Для более сложных объектов используй интерфейс Cloneable:

public class User implements Cloneable {
    private String name;
    private int age;
    private Address address;
    
    @Override
    public User clone() throws CloneNotSupportedException {
        User cloned = (User) super.clone();
        // Глубокое копирование вложенных объектов
        if (this.address != null) {
            cloned.address = this.address.clone();
        }
        return cloned;
    }
}

public class Address implements Cloneable {
    private String street;
    private String city;
    
    @Override
    public Address clone() throws CloneNotSupportedException {
        return (Address) super.clone();
    }
}

// Использование
User user1 = new User("John", 30, new Address("123 Main St", "NYC"));
User user2 = user1.clone();

Способ 4: Использование методов-сеттеров

Частый подход для Bean-объектов:

public class User {
    private String name;
    private int age;
    private Address address;
    
    // Getters и Setters
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
    
    public Address getAddress() { return address; }
    public void setAddress(Address address) { this.address = address; }
}

// Копирование через сеттеры
User user1 = new User();
user1.setName("John");
user1.setAge(30);

User user2 = new User();
user2.setName(user1.getName());
user2.setAge(user1.getAge());
user2.setAddress(new Address(user1.getAddress().getStreet(), user1.getAddress().getCity()));

Способ 5: Сериализация и десериализация (Deep Copy)

Для очень сложных структур:

import java.io.*;

public class ObjectCopyUtil {
    public static <T extends Serializable> T deepCopy(T obj) throws IOException, ClassNotFoundException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(obj);
        oos.close();
        
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bais);
        @SuppressWarnings("unchecked")
        T copy = (T) ois.readObject();
        ois.close();
        
        return copy;
    }
}

// Использование
User user1 = new User("John", 30, new Address("123 Main St", "NYC"));
User user2 = ObjectCopyUtil.deepCopy(user1);

Способ 6: Использование библиотеки MapStruct

Для современных приложений используй MapStruct:

@Mapper
public interface UserMapper {
    User copyUser(User source);
    Address copyAddress(Address source);
}

// Использование
UserMapper mapper = Mappers.getMapper(UserMapper.class);
User user2 = mapper.copyUser(user1);

Сравнение подходов

СпособГлубокое копированиеПроизводительностьСложность
Конструктор копированияДаОтличнаяСредняя
CloneableДаХорошаяСредняя
СеттерыДаХорошаяВысокая
СериализацияДаПлохаяНизкая
MapStructДаОтличнаяНизкая

Рекомендации

  • Для простых объектов: используй конструктор копирования
  • Для Beans: используй MapStruct или конструктор с сеттерами
  • Для сложных структур: реализуй Cloneable
  • Избегай сериализации для копирования — это медленно
  • Помни о вложенных объектах — нужно копировать их отдельно при глубоком копировании