한정적 와일드카드를 사용하자
•
제네릭은 불공변성을 가지기 때문에, List<String>은 List<Object>를 받을 수 없다.
public class Stack<E> {
public Stack();
public void push(E e);
public E pop();
public boolean isEmpty();
public void pushAll(Iterable<E> src) {
for (E e : src)
push(e);
}
}
Java
복사
•
위 Stack 클래스의 pushAll 메서드는 오류나 경고없이 컴파일되지만, Stack<Number>로 선언 후 pushAll(intVal)(intVal은 Integer 타입)을 호출하면 오류가 발생한다.
public void pushAll(Iterable<? extends E> src) {
for (E e : src)
push(e);
}
Java
복사
•
해당 메서드를 위와 같이 extends로 하한 경계 와일드카드(lower bound wildcards)를 적용하여 수정하면 문제없이 잘 동작한다.
public void popAll(Collection<E> dst) {
while (!isEmpty())
dst.add(pop());
}
Java
복사
•
위와 같이 값을 꺼낼 때에도 한정적 와일드 카드를 적용하면 오류 없이 동작 시킬 수 있다.
public void popAll(Collection<? super E> dst) {
while (!isEmpty())
dst.add(pop());
}
Java
복사
•
여기에서는 super로 상한 경계 와일드카드(upper bound wildcards)를 사용했는데, 이와 같이 유연성을 높이기 위해 원소의 생산자나 소비자용 매개변수에 와일드카드를 적용하는 것이 좋다.
•
다만 주의해야할 점은 반환 타입에 한정적 와일드카드 타입을 적용하면, 클라이언트에서 와일드카드를 통해서 받아야하므로 반환 타입에는 와일드카드를 사용하면 안된다.
PECS
•
PECS는 Producer-extends, Consumer-super의 약자로, 매개변수화 타입 T가 생산자라면 <? extends T>를 사용하고 소비자라면 <? super T>를 사용하라는 공식이다.
•
위의 Stack의 예시에서 pushAll의 경우 Stack이 사용할 E 인스턴스를 생산하므로 <? extends E>를 적용하고, popAll의 경우에는 Stack에서 데이터를 꺼내 소비하므로 <? super E>를 적용한다.