[Effective Java] 인스턴스 제어에는 readResolve 메소드보다 enum 타입을 사용하자. |
-
readResolve 메소드는 readObject 메소드에서 생성한 인스턴스를 다른 인스턴스로 바꾸어준다.
만일 역직렬화되는 객체의 클래스에서 readResolve 메소드를 올바르게 정의하면
그 객체가 역직렬화된 후 그 결과로 새롭게 생성된 객체에 대해 이 메소드가 자동 호출되며, 이 메소드에서 반환하는 객체 참조가 역직렬화로 새롭게 생성된 객체 대신 반환된다.
-
싱글톤의 경우 다음과 같은 방법으로 싱글톤을 유지할 수 있다.
private Object readResolve(){
// Deserialization 으로 생성된 새로운 녀석은 GC 된다.
return INSTANCE;
}
-
readResolve 메소드에 의존해서 인스턴스 제어를 한다면,
객체 참조 타입을 갖는 모든 인스턴스 필드는 반드시 transient 로 선언해야 한다.
그렇게 하지 않으면, 침입을 작심한 공격자가 역직렬화된 객체의 readResolve 메소드가 실행되기 전에 그 객체 참조를 획득할 수 있다.
-
readResolve 와 transient 를 사용하여 singleton 의 serialize 를 해결할 수 있지만,
허술하고 많은 주의를 요한다.
가장 좋은 방법은 enum 으로 작성하면 된다는 것이다.
public enum Elvis{
INSTANCE;
....
}
-
readResolve 메소드의 접근성이 중요하다.
readResolve 메소드를 final 클래스에 둘 때는 반드시 private 이 되어야 한다.
final 이 아닌 클래스에 둘 때는 그 메소드의 접근성을 신중하게 고려해야 한다.
만일 readResolve 메소드가 protected 나 public 이면서 그 메소드를 서브 클래스가 오버라이딩 하지 않는다면, 직렬화된 서브 클래스 인스턴스를 역직렬화 할 때 ClassCastException 예외를 발생시킬 수 있는 수퍼 클래스 인스턴스를 생성한다.
Summary
인스턴스 제어에 관련된 불변 규칙이 있어서 그것을 지키게 해야 한다면 enum 타입을 사용해야 한다.
만일 enum 타입을 사용할 수 없고, 직렬화 가능하면서 인스턴스 제어도 해야 하는 클래스가 필요하다면,
그 클래스에 readResolve 메소드를 제공해야 한다.
그리고 그 클래스의 모든 인스턴스 필드가 기본형 타입이나 transient 중 하나가 되도록 해야 한다.
'프로그래밍 놀이터 > 디자인 패턴, 리펙토링' 카테고리의 다른 글
[도서 목차 정리] Effective Java (0) | 2017.03.30 |
---|---|
[Effective Java] 직렬화된 인스턴스 대신 직렬화 프록시의 사용을 고려하자. (0) | 2017.03.28 |
[Effective Java] 방어 가능한 readObject 메소드를 작성하자 (0) | 2017.03.24 |
[Effective Java] 독자적인 직렬화 형태의 사용을 고려하자 (0) | 2017.03.23 |
[Effective Java] Serializable 인터페이스를 분별력 있게 구현하자. (0) | 2017.03.21 |
댓글