Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Поверхностное копирование (Shallow Copy)
Поверхностное копирование — это создание копии объекта, при котором копируются только значения примитивных полей и ссылки на объекты, но не сами вложенные объекты. Это означает, что оригинальный объект и его копия будут ссылаться на одни и те же вложенные объекты в памяти.
Контрастное сравнение: Поверхностное vs Глубокое копирование
Поверхностное копирование:
- Копируются только примитивные значения
- Ссылки на объекты остаются теми же
- Экономно по памяти
- Может привести к неожиданным побочным эффектам
Глубокое копирование:
- Копируются все данные, включая вложенные объекты
- Каждый объект имеет отдельную копию
- Требует больше памяти
- Полностью независимые копии
Пример поверхностного копирования
class Address {
public String city;
public String country;
public Address(String city, String country) {
this.city = city;
this.country = country;
}
}
class Person {
public String name;
public Address address; // Вложенный объект
public Person(String name, Address address) {
this.name = name;
this.address = address;
}
}
// Поверхностное копирование
Address addr = new Address("Moscow", "Russia");
Person original = new Person("Alice", addr);
// Простое копирование по ссылке (плохой способ)
Person shallowCopy = original; // Обе переменные указывают на одно место в памяти
// Когда изменяем данные
original.address.city = "Saint Petersburg";
// Изменения видны в обеих переменных!
System.out.println(original.address.city); // Saint Petersburg
System.out.println(shallowCopy.address.city); // Saint Petersburg (проблема!)
Реальное поверхностное копирование через создание нового объекта
class Person implements Cloneable {
public String name; // Примитивный тип (строка - это специальный случай)
public Address address;
public Person(String name, Address address) {
this.name = name;
this.address = address;
}
// Поверхностное копирование через Object.clone()
@Override
public Person clone() throws CloneNotSupportedException {
return (Person) super.clone(); // Создаёт новый объект, но ссылки остаются теми же
}
}
// Использование
Address addr = new Address("Moscow", "Russia");
Person original = new Person("Alice", addr);
Person shallowCopy = original.clone();
// Примитивное поле скопировалось
shallowCopy.name = "Bob";
System.out.println(original.name); // Alice (независимо)
System.out.println(shallowCopy.name); // Bob (независимо)
// Но объект address остался тем же!
shallowCopy.address.city = "Saint Petersburg";
System.out.println(original.address.city); // Saint Petersburg (проблема!)
System.out.println(shallowCopy.address.city); // Saint Petersburg (одинаково)
Поверхностное копирование с массивами
int[] original = {1, 2, 3, 4, 5};
int[] shallowCopy = original; // Просто ссылка, не копирование
shallowCopy[0] = 99;
System.out.println(original[0]); // 99 (изменение видно в original)
// Правильное поверхностное копирование массива
int[] properShallowCopy = new int[original.length];
System.arraycopy(original, 0, properShallowCopy, 0, original.length);
properShallowCopy[0] = 100;
System.out.println(original[0]); // 99 (не изменилось)
System.out.println(properShallowCopy[0]); // 100
Поверхностное копирование с коллекциями
List<String> original = new ArrayList<>(Arrays.asList("A", "B", "C"));
// Поверхностное копирование через конструктор
List<String> shallowCopy = new ArrayList<>(original);
// Изменение элементов списка
shallowCopy.set(0, "X");
System.out.println(original.get(0)); // A (независимо)
System.out.println(shallowCopy.get(0)); // X
// Пример с объектами внутри списка
List<Person> originalList = new ArrayList<>();
originalList.add(new Person("Alice", new Address("Moscow", "Russia")));
List<Person> shallowCopyList = new ArrayList<>(originalList);
// Изменяем объект Person внутри списка
shallowCopyList.get(0).address.city = "SPB";
System.out.println(originalList.get(0).address.city); // SPB (проблема!)
Поверхностное копирование с Map
Map<String, Address> original = new HashMap<>();
original.put("home", new Address("Moscow", "Russia"));
original.put("work", new Address("SPB", "Russia"));
// Поверхностное копирование
Map<String, Address> shallowCopy = new HashMap<>(original);
// Изменение значения в копии
shallowCopy.get("home").city = "Kazan";
System.out.println(original.get("home").city); // Kazan (та же ссылка!)
Когда использовать поверхностное копирование
- Когда вложенные объекты не изменяются: Если Address является immutable, поверхностного копирования достаточно
- Для производительности: Когда нужно быстро скопировать объект с большим количеством вложенных данных
- Специальные случаи: Когда необходимо сохранить ссылки на те же объекты
Когда это становится проблемой
// Опасный код
Person person1 = new Person("Alice", new Address("Moscow", "Russia"));
Person person2 = new Person("Bob", person1.address); // Ошибка дизайна!
// Если изменить адрес в person1, он изменится и в person2
person1.address.city = "SPB";
System.out.println(person2.address.city); // SPB (неожиданно!)
Итоговые замечания
Поверхностное копирование — это низкоуровневая операция, которая часто используется в Java неосознанно. Разработчик должен чётко понимать, работает ли он с примитивными типами или с объектами, чтобы избежать ошибок. Для сложных структур рекомендуется использовать глубокое копирование или создавать новые объекты явно, чтобы избежать неожиданных побочных эффектов.