Коли потрібно робити захисну копію (defensive copy)?
Захисну копію потрібно робити, коли ваш клас отримує від когось або віддає комусь змінні дані.
Junior Level
Захисну копію потрібно робити, коли ваш клас отримує від когось або віддає комусь змінні дані.
Коли робити копію
1. При отриманні даних (в конструкторі)
// Для повністю незмінного класу немає сетерів.
// Цей приклад показує Builder pattern або конструктор з копіюванням:
public class MyClass {
private final List<String> items;
public MyClass(List<String> items) {
this.items = new ArrayList<>(items); // defensive copy в конструкторі
}
}
2. При поверненні даних (в гетері)
public List<String> getItems() {
return new ArrayList<>(items); // копія вихідних даних
}
Коли НЕ потрібно робити копію
- Примітиви (
int,boolean) — вони не змінні String— незмінний- Внутрішні дані, які ніколи не покидають клас
Middle Level
Основні сценарії
А. Масиви
public class MyClass {
private final int[] numbers;
public MyClass(int[] numbers) {
this.numbers = numbers.clone(); // або Arrays.copyOf(numbers)
}
public int[] getNumbers() {
return numbers.clone();
}
}
Б. Колекції
this.list = List.copyOf(input); // Java 10+
this.list = new ArrayList<>(input); // Java 8
В. Date
this.date = new Date(date.getTime());
Коли копіювання НЕ потрібне
- Незмінні типи —
String,BigDecimal,LocalDate,Integer - Private дані — об’єкт створено всередині класу і ніколи не покидає його
- Transfer Objects — якщо клас за дизайном є змінним DTO
- Mutable DTO / Builder pattern — об’єкти за дизайном змінні
- Примітиви та обгортки (int, Integer, String) — незмінні за природою
Copy vs Unmodifiable
- В конструкторі — лише Copy (
new ArrayList(original)) - В гетері — можна Copy або Unmodifiable (
Collections.unmodifiableList(original))
// List.copyOf викидає NPE при null елементах, new ArrayList — допускає.
Senior Level
TOCTOU та порядок операцій
Копіюйте перед валідацією:
public SecureConfig(Map<String, String> config) {
Map<String, String> copy = new HashMap<>(config); // спочатку копія
if (!copy.containsKey("auth")) throw new IllegalStateException(); // потім перевірка
this.config = Map.copyOf(copy);
}
Без цього в багатопотоковому середовищі мапа може змінитися після перевірки, але до збереження.
Продуктивність
List.copyOf()— оптимізований в JDK 10+, може повернути той самий об’єкт якщо вхід вже незмінний- Для великих колекцій у гарячих циклах розгляньте персистентні структури даних (Vavr)
- Уникайте глибокого копіювання величезних графів об’єктів
Резюме для Senior
- Робіть копії всього, що може бути змінено ззовні
- Спочатку копіюйте, потім валідуйте
- Використовуйте
List.copyOf()для сучасного захисного копіювання - Не копіюйте величезні масиви в “гарячих” циклах без необхідності
- Розрізняйте обгортку та копію: обгортка не захищає від змін оригіналу
🎯 Шпаргалка для інтерв’ю
Обов’язково знати:
- Копіювати при отриманні (конструктор) та при поверненні (гетер) змінних даних
- НЕ потрібно копіювати: примітиви, String, LocalDate, Integer, private дані
- Масиви:
numbers.clone()абоArrays.copyOf() - Колекції:
List.copyOf(input)(Java 10+) абоnew ArrayList<>(input)(Java 8) - Date:
new Date(date.getTime()) - Copy vs Unmodifiable: в конструкторі — лише Copy, в гетері — Copy або Unmodifiable
- TOCTOU: спочатку копіюйте, потім валідуйте
Часті уточнюючі запитання:
- Коли копіювання НЕ потрібне? — Незмінні типи, private дані, Transfer Objects
List.copyOfvsnew ArrayList?* — List.copyOf повертає незмінний; new ArrayList — змінний- Що якщо колекція величезна? — Розгляньте персистентні структури (Vavr) або COW
- List.copyOf допускає null? — Ні, викине NPE; new ArrayList допускає
Червоні прапорці (НЕ говорити):
- «Defensive copy потрібен для всіх типів» — примітиви та String не потрібно
- «Можна змінити змінний ключ в HashMap» — об’єкт загубиться в бакеті
- «UnmodifiableList в конструкторі — захист» — це обгортка, не копія
- «Копіювання після валідації — безпечно» — TOCTOU-атака можлива
Пов’язані теми:
- [[9. Що робити, якщо поле класу посилається на змінний об’єкт]]
- [[10. Що таке захисна копія (defensive copy)]]
- [[12. Як захистити колекцію від змін]]
- [[13. Що таке Collections.unmodifiableList() і як це працює]]
- [[29. Як правильно працювати з колекціями в незмінних класах]]