[Effective Java 3/e] 아이템 33 - 타입 안전 이종 컨테이너를 고려하라


아이템 33 - 타입 안전 이종 컨테이너를 고려하라

이종 컨테이너 패턴

  • 컨테이너 대신 키를 매개변수화한 다음, 컨테이너에 값을 넣거나 뺄 때 매개변수화한 키를 함께 제공
    • 값의 타입이 키와 같음을 보장

타입 안전 이종 컨테이너 패턴

public class Favorites {

  private Map<Class<?>, Object> favorites = new HashMap<>();
  
  public <T> putFavorite(Class<T> type, T instance) {
    favorites.put(Objects.requireNonNull(type), instance);
  }

  public <T> getFavorite(Class<T> type) {
    return type.cast(favorites.get(type));
  }

  public static void main(String[] args) {
    Favorites f = new Favorites();

    f.putFavorite(String.class, "Java");
    f.putFavorite(Integer.class, 0xcafebabe);
    f.putFavorite(Class.class, Favorites.class);

    String favoriteString = f.getFavorite(String.class);
    int favoriteInteger = f.getFavorite(Integer.class);
    Class<?> favoriteClass = f.getFavorite(Class.class);

    System.out.printf("%s %x %s%n", favoriteString, favoriteInteger, favoriteClass.getName());
  }
  
}

// output : Java cafebabe Favorites

동적 형변환으로 런타임 타입 안전성 확보

public <T> putFavorite(Class<T> type, T instance) {
  favorites.put(Objects.requireNonNull(type), type.cast(instance));
}

asSubclass를 사용해 한정적 타입 토큰을 안전하게 형변환한다

static Annotation getAnnotation(AnnotatedElement element, String annotationTypeName) {
  Class<?> annotationType = null; // 비한정적 타입 토큰
  try {
    annotationType = Class.forName(annotationTypeName);
  } catch (Exception ex) {
    throw new IllegalArgumentException(ex);
  }
  return element.getAnnotation(annotationType.asSubclass(Annotation.class));
}
  • 컴파일 시점에는 타입을 알 수 없는 에너테이션을 asSubclass 메서드를 사용해 런타임에 읽어내는 방법