#28 바운드 와일드카드를 사용해서 API의 유연성을 높이자
이 Stack 클래스에 연속된 요소들을 받아서 push 하는 pushAll 메서드를 추가하면 아래와 같습니다.
만약 Iterable 객체의 요소 타입 와 Stack의 요소 타입이 일치(Integer = Integer)하면 이 메서드는 문제없이 잘 동작합니다.
하지만 이 둘이 일치하지 않으면(Number != Integer) 아래와 같이 컴파일 에러가 발생합니다.
Number와 Integer가 상속 관계이지만, 제네릭의 매개변수화 타입은 불변(invariant) 타입이므로 상속 관계가 무의미 해지기 때문입니다.
이 문제를 해결하기 위해 바운드 와일드카드 타입(bounded wildcard type)을 이용할 수 있습니다.
Iterable<? extends E>로 표현하며, 이는 "E의 서브 타입 요소를 가진 Iterable"이라는 의미를 가집니다.
아래와 같이 Iterable<? extends Number>는 Number를 상속받는 Integer, Double, Long 타입 요소를 가질 수 있습니다.
Stack 클래스에서 요소들을 꺼내어 주어진 컬렉션에 추가하는 popAll 메서드입니다.
만약 Collection 객체의 요소 타입 와 Stack의 요소 타입이 일치(Object = Object)하면 이 메서드는 문제없이 잘 동작합니다.
하지만 이 둘이 일치하지 않으면(Object != Number) 아래와 같이 컴파일 에러가 발생합니다.
Object와 Number가 상속 관계이지만, 제네릭의 매개변수화 타입은 불변(invariant) 타입이므로 상속 관계가 무의미 해지기 때문입니다.
이 문제를 해결하기 위해 바운드 와일드카드 타입(bounded wildcard type)을 이용할 수 있습니다.
Collection<? super E>로 표현하며, 이는 "E의 슈퍼 타입 요소를 가진 Collection"이라는 의미를 가집니다.
아래와 같이 Collection<? super Number>는 Number의 슈퍼 클래스인 Object타입 요소를 가질 수 있습니다.
유연성을 극대화하려면 상황에 따라 적절한 와일드카드 타입을 이용해야 하는데, 이때 PESC를 따르는 게 좋습니다.
PECS : producer(생산자)-extends, consumer(소비자)-super
매개 변수 타입이 T 생산자를 나타내면 <? extends T>, T 소비자를 나타내면 <? super T>를 이용하면 됩니다.
위에서 본 pushAll 메서드는 Stack에서 이용하는 E 인스턴스를 생산하므로, Iterable<? extends E>.
popAll 메서드는 Stack으로부터 E 인스턴스를 소비하므로 Collection<? super E>입니다.