Effective Java ‐ Item 89⚠️ - dnwls16071/Backend_Summary GitHub Wiki

아이템 89 - 인스턴스 수를 통제해야 한다면 readResolve보다는 열거 타입을 사용하라

  • 싱글턴으로 구현된 클래스는 인스턴스를 하나만 만들어지는 것을 보장한다.

싱글턴을 직렬화하는 경우 문제점

  • 클래스에 implements Serializable 을 추가하는 순간 더 이상 싱글턴이 아니게 된다.
  • 기본 직렬화를 쓰지 않더라도, 그리고 명시적인 readObject를 제공하더라도 소용없다.
  • 어떤 readObject를 사용하든 이 클래스가 초기화될 때 만들어진 인스턴스와는 별개인 인스턴스를 반환하게 된다.

readResolve 기능을 이용하는 경우

  • readObject가 만들어낸 인스턴스를 다른 것으로 대체할 수 있다.
  • 역직렬화한 객체의 클래스readResolve 메서드를 적절히 정의해뒀다면, 역직렬화 후 새로 생성된 객체인수로 이 메서드가 호출* 이 메서드가 반환한 객체 참조가 새로 생성된 객체를 대신해 반환된다.
  • 대부분의 경우 이때 새로 생성된 객체의 참조는 유지하지 않으므로 바로 가비지 컬렉션 대상이 된다.

Serializable의 구현과 readResolve 메서드 제공

  • 싱글턴의 속성을 유지하기 위한 방법
    • readResolve()
      • 역직렬화한 객체는 무시하고 클래스 초기화 때 만들어진 인스턴스를 반환
      • 이때 인스턴스의 직렬화 형태는 아무런 실 데이터를 가질 이유가 없기 때문에 모든 인스턴스 필드를 transient로 선언
  • readResolve()를 인스턴스 통제 목적으로 사용하려는 경우
    • 객체 참조 타입 인스턴스 필드는 모두 transient로 선언해야 한다.

readResolve 메서드의 접근성에 대한 이야기

  • final 클래스인경우 readResolve 메서드는 private 접근 제한자 이어야 한다.

final 이 아닌 클래스의 경우 주의사항

  • 접근 제한자 설정시
    • private으로 선언하면 하위 클래스에서 사용할 수 없다.
    • package-private으로 선언하면 같은 패키지에 속한 하위 클래스에서만 사용할 수 있다.
    • protectedpublic으로 선언하면 이를 재정의하지 않은 모든 하위 클래스에서 사용할 수 있다.
    • protectedpublic이면서 하위 클래스에서 재정의 하지않았다면, 하위 클래스의 인스턴스를 역직렬화하면 상위 클래스의 인스턴스를 생성하여 ClassCastException을 일으킬 수 있다.