Growth-Collectors / effective-java

repository for effective java study
3 stars 2 forks source link

아이템 88. readObject 메서드는 방어적으로 작성하라 #90

Open HanaHww2 opened 1 year ago

Tldkt commented 1 year ago

readObject에서 주의사항

1. 방어적 복사를 수행하는 불변 클래스 개선하기

readObject()

유효성 검사를 먼저 하는 경우에도 어차피 객체 불변성을 보장하기 위해서는 방어적 복사를 해야 하기 때문

방어적 복사(Defensive Copy)?

Serializable 만 구현하면 불변식을 보장할 수 있을까?

→ 아님! readObject 메서드도 생성자만큼이나 주의해야 함

2. 예시와 함께 보기

public final class Period {
    private final Date start;
    private final Date end;

    /**
     * @param  start 시작 시각
     * @param  end 종료 시각; 시작 시각보다 뒤여야 한다.
     * @throws IllegalArgumentException 시작 시각이 종료 시각보다 늦을 때 발생한다.
     * @throws NullPointerException start나 end가 null이면 발생한다.
     */
    public Period(Date start, Date end) {
        this.start = new Date(start.getTime()); // 가변인 Date 클래스의 위험을 막기 위해 새로운 객체로 방어적 복사
        this.end = new Date(end.getTime());

        if (this.start.compareTo(this.end) > 0) {
            throw new IllegalArgumentException(start + " after " + end);
        }
    }

    public Date start() { return new Date(start.getTime()); }
    public Date end() { return new Date(end.getTime()); }
    public String toString() { return start + " - " + end; }
    // ... 나머지 코드는 생략
}

Period 클래스의 생성자에서

하지만, Period 클래스는 여전히 불변식을 보장하지 못함

Period period = new Period(new Date(), new Date());
Date end = period.end();
end.setYear(100);

Period 객체를 생성한 후, end 필드가 참조하는 Date 객체를 얻어와서 해당 객체의 연도를 100년으로 수정하게 됨

→ 따라서 Date 클래스 대신 불변한 LocalDateTime 클래스나 Instant 클래스 등을 사용해야 하며, start와 end 필드가 참조하는 객체를 완전히 복사하는 방식으로 방어적 복사해야 함

3. 정리하면