[Effective Java 3/e] 아이템 19 - 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라


아이템 19 - 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라

메서드 재정의 시 주의사항

  • 상속용 클래스는 재정의할 수 있는 메서드들을 내부적으로 어떻게 이용하는지(자기사용) 문서로 남겨야 한다.
  • 클래스의 내부 동작 과정 중간에 끼어들 수 있는 훅(hook)을 잘 선별하여 protected 메서드 형태로 공개해야 할 수도 있다.

상속용 클래스 설계 시 메서드의 protected 노출 기준

  • 직접 하위 클래스를 만들어보는 것
    • 상속용으로 설계한 클래스는 배포 전에 반드시 하위 클래스를 만들어 검증해야 한다.
  • 상속용 클래스의 생성자는 직접적으로든 간접적으로든 재정의 가능 메서드를 호출해서는 안 된다.

잘못된 예 - 생성자가 재정의 가능 메서드를 호출

public class Super {
  public Super() {
    overrideMe();
  }

  public void overrideMe() {
  
  }
}

public final class Sub extends Super {
  private final Instant instant;

  Sub() {
    instant = Instant.now();
  }

  @Override public void overrideMe() {
    System.out.println(instant);
  }

  public static void main(String[] args) {
    Sub sub = new Sub();
    sub.overrideMe();
  }
}
  • 첫 번째는 null을 출력
    • 상위 클래스의 생성자는 하위 클래스의 생성자가 인스턴스 필드를 초기화하기도 전에 overrideMe를 호출

Cloneable과 Serializable

  • clone과 readObject 모두 직접적으로든 간접적으로든 재정의 가능 메서드를 호출해서는 안 된다.
  • Serializable을 구현한 상속용 클래스가 readResolve나 writeReplace 메서드를 갖는다면 이 메서드들을 private이 아닌 protected로 선언해야 한다.

상속용으로 설계하지 않은 클래스의 상속 금지하는 방법

  • 클래스를 final로 선언
  • 모든 생성자를 private이나 package-private로 선언하고 public 정적 팩터리를 만들어준다.