티스토리 뷰
생성자를 통해 초기화 할 때, 새로운 객체로 감싸서 복사해주는 방법입니다.
외부와 내부에서 주소값을 공유하는 인스턴스의 관계를 끊어주기 위함입니다.
(예를 들어 외부에서 add했는데, 내부에 add가 반영되는 경우)
public School(Student[] students) {
this.school = new ArrayList<>(students);
}
방어적 복사 이용
만약 생성자에서 유효성 검증이 필요하다고 합시다.
일반적으로는 아래와 같이 넘어온 값을 검증하고 객체 내부변수에 검증된 값을 할당해주는 순서가 맞다고 생각할 수 있습니다.
public Period(Date start, Date end) {
if (validation(start, end)) {
throw new IllegalArgumentException("");
}
this.start = start;
this.end = end;
}
하지만 Date같은 경우는 값이 변경될 수 있으므로 생성자에서 매개변수의 유효성을 검사하기 전에 방어적 복사본을 만들고, 이 복사본을 이용해서 유효성을 검증합니다.
만약 멀티쓰레딩 환경일 경우 유효성 검사부터 후 복사본을 만드는 사이에 원본 값이 변경될 위험이 있기 때문입니다.
public Period(Date start, Date end) {
this.start = new Date(start.getTime()); // 방어적 복사
this.end = new Date(end.getTime()); // 방어적 복사
if (validation(start, end)) {
throw new IllegalArgumentException("");
}
}
clone을 사용해서 본사본을 만들 수도 있지만, 생성자의 매개변수가 final 클래스가 아니어서 확장될 수 있는 타입이면 방어적 복사본을 만들때 clone을 사용하면 안 됩니다.(재정의된 clone이 호출될 수 있기 때문)
하지만 생성자에서만 복사본을 만든다고 내부 값을 변경할 수 없는 것은 아닙니다.
getter로 얻은 객체를 통해 얼마든지 내부 값이 변경될 수 있습니다.
// Before
List<School> schoolList = school.getList();
schoolList.add();
// Before
period.getStart().setTime();
따라서 getter에서도 복사본을 리턴해줘야합니다.
// After
public List<School> toList() {
return Collections.unModifiableList(school);
}
// After
public Date getStart() {
return new Date(start.getTime());
}
생성자의 매개변수로 프리미티브 타입이 넘어온다면 애초에 값이 복사되어 전달되므로 유효성검사 후 그냥 할당해줘도 되지만, 생성자의 매개변수로 객체가 넘어온다면 먼저 복사본을 만든 후 유효성 검사를 해주는 것이 좋습니다.
즉, 불변성이 유지된다면 검증부터 해줘도 되지만 그걸 보장할 수 없다면 복사본을 만든 후, 복사본으로 검증해주는 것이 좋습니다.
또 getter도 복사본을 리턴해줘야 완벽한 캡슐화라고 볼 수 있습니다.
참고 자료
[Java] 방어적 복사(Defensive copy)
생성자를 통해 초기화 할 때, 새로운 객체로 감싸서 복사해주는 방법이다.만약 생성자에서 유효성 검증이 필요하다고 하자. 일반적으로는 아래와 같이 넘어온 값을 검증하고 객체 내부변수에
velog.io
'JAVA' 카테고리의 다른 글
JVM의 구조와 Java의 실행방식 (0) | 2022.07.24 |
---|---|
오브젝트의 동일성과 동등성 (0) | 2022.07.10 |
java에서 멀티쓰레드 [3] Callable과 Future (0) | 2022.02.07 |
java에서 멀티쓰레드 [2] Executors와 ExecutorService (0) | 2022.02.07 |
java에서 멀티쓰레드 [1] Thread와 Runnable (0) | 2022.02.07 |
- Total
- Today
- Yesterday
- kotest
- 코테
- programmers
- BAEKJOON
- Spring
- 디자인 패턴
- 알고리즘
- Algorithm
- JPA
- node.js
- 이펙티브 자바
- AWS
- Kotlin
- 디자인패턴
- 클린 코드
- C++
- 클린 아키텍처
- 프로그래머스
- 정규표현식
- 이팩티브 자바
- Olympiad
- kkoon9
- BOJ
- Effective Java
- 객체지향
- Spring Boot
- Java
- 테라폼
- 백준
- MSA
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |