// 코드 50-1 기간을 표현하는 클래스 - 불변식을 지키지 못했다. (302-305쪽) publicfinalclassPeriod { privatefinal Date start; privatefinal Date end;
/** * @param start 시작 시각 * @param end 종료 시각. 시작 시각보다 뒤여야 한다. * @throws IllegalArgumentException 시작 시각이 종료 시각보다 늦을 때 발생한다. * @throws NullPointerException start나 end가 null이면 발생한다. */ publicPeriod(Date start, Date end) { if (start.compareTo(end) > 0) thrownewIllegalArgumentException( start + "가 " + end + "보다 늦다."); this.start = start; this.end = end; }
public Date start() { return start; } public Date end() { return end; }
// '불변'인 Period의 내부를 공격하는 두 가지 예 (303-305쪽) publicclassAttacks { publicstaticvoidmain(String[] args) { // 코드 50-2 Period 인스턴스의 내부를 공격해보자. (303쪽) Datestart=newDate(); Dateend=newDate(); Periodp=newPeriod(start, end); end.setYear(78); // p의 내부를 변경했다! System.out.println(p);
// 코드 50-4 Period 인스턴스를 향한 두 번째 공격 (305쪽) start = newDate(); end = newDate(); p = newPeriod(start, end); p.end().setYear(78); // p의 내부를 변경했다! System.out.println(p); } }
실행결과
1 2 3 4 5
Thu Feb 14 14:00:33 KST 2019 - Tue Feb 14 14:00:33 KST 1978 Thu Feb 14 14:00:33 KST 2019 - Tue Feb 14 14:00:33 KST 1978
// '불변'인 Period의 내부를 공격하는 두 가지 예 (303-305쪽) publicclassAttacks { publicstaticvoidmain(String[] args) { // 코드 50-2 Period 인스턴스의 내부를 공격해보자. (303쪽) Datestart=newDate(); Dateend=newDate(); Periodp=newPeriod(start, end); end.setYear(78); // p의 내부를 변경했다! System.out.println(p);
// 코드 50-4 Period 인스턴스를 향한 두 번째 공격 (305쪽) start = newDate(); end = newDate(); p = newPeriod(start, end); p.end().setYear(78); // p의 내부를 변경했다! System.out.println(p); } }
실행결과
1 2 3 4 5
Thu Feb 14 14:08:43 KST 2019 - Thu Feb 14 14:08:43 KST 2019 Thu Feb 14 14:08:43 KST 2019 - Thu Feb 14 14:08:43 KST 2019
Process finished with exit code 0
위에 코드처럼 방어적으로 복사를 하여 참조를 통한 공격이 통하지 않게 할수도 있다.
매개변수를 검사하기 전에 방어적 복사본을 만들고 유호성을 검사해야 된다 멀티쓰레드 환경에서 해당 값을 다른쓰레드가 바꿀수도 있어서 이다.