Item28에서 정리했던 것 처럼 매개변수화 타입은 불공변(invariant)입니다. 즉, List<String>은 List<Object>의 하위타입이 아닙니다.
일반적으로는 이렇게 되는 것이 맞는 것 같습니다. 하지만 List<Number>에 Integer 타입을 추가하고 싶을 때가 있습니다. 매개변수화 타입은 불공변이기 때문에 불가능하지만 해결책은 있습니다. 한정적 와일드카드를 이용하는 것 입니다.
한정적 와일드 카드(Bounded Wildcards)
- Upper Bounded Wildcards: 타입제한을 풀어줄 때 사용, 제네릭 타입을 상위 제네릭 타입으로 묶을 때 사용 (List<? extends Number>)
- Lower Bounded Wildcards: 타입을 제한할 때 사용, 유연성을 위해 지정된 타입의 상위타입만 허용할 때 사용 (List<? super Integer>)
둘 모두 자기 자신도 포함합니다. 즉 List<? super Integer>에는 Integer타입도 가능합니다.
아래의 결함이 있는 Stack 클래스를 보면서 실습해보겠습니다.
public class Stack<E> {
public void push(E e) { ... }
public E pop() { ... }
public boolean isEmpty() { ... }
public void pushAll(Iterable<E> src) {
for (E e : src) {
push(e);
}
}
public void popAll(Collection<E> dst) {
while (!isEmpty()) {
dst.add(pop());
}
}
}
Stack<Number>에 Iterable<Integer>를 pushAll하거나 Collection<Object>를 popAll하고 싶을 때는 아래와 같이 바꿀 수 있습니다.
public void pushAll(Iterable<? extends E> src) { ... }
public void popAll(Collection<? super E> dst) { ... }
이처럼 유연성을 극대화하려면 원소의 생산자나 소비자용 입력 매개변수에 한정적 와일드카드 타입을 사용합니다. 한편, 입력 매개변수가 생산자와 소비자 역할을 동시에 한다면 타입을 정확하게 지정해야 하므로 와일드카드 타입을 사용하면 안됩니다.
팩스(PECS): producer-extends, consumer-super
위의 공식을 외우면 어떤 와일드카드 타입을 사용하는지 기억하는데 도움이 됩니다.
이때 주의할 점은 반환 타입에는 한정적 와일드카드 타입을 사용하면 안된다는 것 입니다.
반응형
'스터디 > 이펙티브 자바' 카테고리의 다른 글
[Effective Java] Item33. 타입 안전 이종 컨테이너를 고려 (0) | 2022.06.19 |
---|---|
[Effective Java] Item32. 제네릭과 가변인수를 함께 쓸 때는 신중하게 (0) | 2022.06.18 |
[Effective Java] Item30. 이왕이면 제네릭 메서드로 (0) | 2022.06.18 |
[Effective Java] Item29. 이왕이면 제네릭 타입으로 (0) | 2022.06.12 |
[Effective Java] Item28. 배열보다는 리스트 (0) | 2022.06.12 |