아이템33 타입 안전 이종 컨테이너를 고려하라
Effective Java 3e 아이템 33를 요약한 내용 입니다.
제네릭은 Set<E>
, Map<K,V>
등의 컬렉션과 ThreadLocal<T>
, AtomicReference<T>
등의 단일 원소 컨테이너에도 흔히 쓰인다. 예컨대 Set
에는 원소의 타입을 뜻하는 단 하나의 타입 매개변수만 있으면 되며, Map
에는 키와 값의 타입을 뜻하는 2개만 필요한 식이다.
더 유연한 수단이 필요할 때도 종종 있다.
데이터베이스의 행(row)
은 임의 개수의 열(column)
을 가질 수 있는데, 모두 열을 타입 안전하게 이용할 수 있다면 멋질 것이다.
다행히 쉬운 해법이 있다.
컨테이너
대신 키를 매개변수화한 다음, 컨테이너에 값을 넣거나 뺄 때 매개변수화
한 키를 함께 제공하면 된다. 이런 설계 방식을 타입 안전 이종 컨테이너 패턴
이라 한다.
Favorites 인스턴스는 타입 안전하다. 따라서 Favorites는 타입 안전 이종 컨테이너
라 할 만하다.
비한정적 와일드카드 타입
이라 이 맵 안에 아무것도 넣을 수 없다고 생각할 수 있지만, 사실은 그 반대다. 와일드카드 타입이 중첩 되었다는 점을 깨달아야 한다.
와일드 타입이 중첩되었다는 말은 무슨 뜻일까?
이는 모든 키가 서로 다른 매개변수화타입일 수 있다는 뜻으로, 첫 번째는 Class<String>, 두 번째는 Class<Integer>식으로 될 수 있다.
Favorite
클래스에는 알아두어야 할 제약이 두 가지 있다.
Favorite
클래스에는 알아두어야 할 제약이 두 가지 있다.악의적인 클라이언트가 Class 객체를 (제네릭이 아닌)
로 타입
(아이템 26)으로 넘기면 Favorite 인스턴스의타입 안전성
이 쉽게 깨진다. 하지만 이는 클라이언트 코드에서 컴파일할 때비검사 경고
가 뜰 것이다.Favorites가
타입 불변식
을 어기는 일이 없도록 보장하려면putFavorite
메서드와 같이instance
의 타입이type
으로 명시한 타입과 같은지 확인하면 된다.java.util.Collections
에는checkedSet
,checkedList
,checkedMap
같은 메서드가 있는데 바로 이 방식을 적용한 컬렉션 래퍼들이다.Favorites 클래스의 두 번째 제약은
실체화 불가 타입
에는 사용할 수 없다는 것이다. 다시 말해, 즐겨 찾는String
이나String[]
은 저장할 수 있어도 즐겨 찾는 List<String>은 저장할 수 없다.List<String>
을 저장하려는 코드는 컴파일되지 않을 것이다.List<String>
용Class
객체를 얻을 수 없기 때문이다.List<String>.class
라고 쓰면 문법 오류가 난다.List<String>
과List<Integer>
는List.class
라는 객체를 공유하기 때문이다.이는
한정적 타입 토큰
을 활용하면 가능하다. 한정적 타입 토큰이란 단순히 한정적 타입 매개변수나 한정적 와일드카드를 사용하여 표현 가능한 타입을 제한하는 타입 토큰이다.애너테이션 API(아이템 39)는 한정적 타입 토큰을 적극적으로 사용한다.
여기서
annotationType
인수는 애너테이션 타입을 뜻하는 한정적 타입 토큰이다. 이 메서드는 토큰으로 명시한 타입의 에너테이션이 대상 요소에 달려 있다면 그 애너테이션을 반환하고 없다면null
을 반환한다. 즉, 애너테이션된 요소는 그 키가 애너테이션 타입인, 타입 안전 이종 컨테이너이다.
Class<?>
타입의 객체가 있고, 이를 (getAnnotation
처럼) 한정적 타입 토큰을 받는 메서드에 넘기려면 어떻게 해야 할까?
객체를 Class<? extends Annotation>
으로 형변환할 수도 있지만 이 형변환은 비검사
이므로 컴파일하면 경고가 뜻 것이다. 운 좋게도 Class
클래스가 이런 형변환을 안전하게 수행해주는 인스턴스 메서드를 제공한다. 바로 asSubClass
메서드로, 호출된 인스턴스 자신의 Class
객체를 인수가 명시한 클래스로 형변환한다. (형변환된다는 것은 이 클래스가 인수로 명시한 클래스의 하위 클래스라는 뜻이다.)
정리
컬렉션 API
로 대표되는 일반적인 제네릭 형태에서는 한 컨테이너가 다룰 수 있는 타입 매개변수
의 수가 고정되어 있다. 하지만 컨테이너 자체가 아닌 키를 타입 매개변수
로 바꾸면 이런 제약이 없는 타입 안전 이종 컨테이너
를 만들 수 있다. 타입 안전 이종 컨테이너는 Class
를 키로 쓰며, 이런 식으로 쓰이는 Class
객체를 타입 토큰이라 한다.
Last updated