brunch

You can make anything
by writing

C.S.Lewis

by 이승현 May 14. 2018

제네릭(Generics)

#28 바운드 와일드카드를 사용해서 API의 유연성을 높이자

Effective Java - 제네릭(Generics)


#28 바운드 와일드카드를 사용해서 API의 유연성을 높이자


Upper bounded wildcard


#01 Stack class


이 Stack 클래스에 연속된 요소들을 받아서 push 하는 pushAll 메서드를 추가하면 아래와 같습니다.

#02 pushAll 메서드


만약 Iterable 객체의 요소 타입 와 Stack의 요소 타입이 일치(Integer = Integer)하면 이 메서드는 문제없이 잘 동작합니다.

하지만 이 둘이 일치하지 않으면(Number != Integer) 아래와 같이 컴파일 에러가 발생합니다.

Number와 Integer가 상속 관계이지만, 제네릭의 매개변수화 타입은 불변(invariant) 타입이므로 상속 관계가 무의미 해지기 때문입니다.

#03 pushAll 메서드


이 문제를 해결하기 위해 바운드 와일드카드 타입(bounded wildcard type)을 이용할 수 있습니다.

Iterable<? extends E>로 표현하며, 이는 "E의 서브 타입 요소를 가진 Iterable"이라는 의미를 가집니다.

#04 와일드 카드타입 pushAll 메서드


아래와 같이 Iterable<? extends Number>는 Number를 상속받는 Integer, Double, Long 타입 요소를 가질 수 있습니다.


#05 바운드 와일드카드 타입




Lower bounded wildcard


Stack 클래스에서 요소들을 꺼내어 주어진 컬렉션에 추가하는 popAll 메서드입니다.

#06 popAll 메서드


만약 Collection 객체의 요소 타입 와 Stack의 요소 타입이 일치(Object = Object)하면 이 메서드는 문제없이 잘 동작합니다.

하지만 이 둘이 일치하지 않으면(Object != Number) 아래와 같이 컴파일 에러가 발생합니다.

Object와 Number가 상속 관계이지만, 제네릭의 매개변수화 타입은 불변(invariant) 타입이므로 상속 관계가 무의미 해지기 때문입니다.

#07 popAll 메서드


이 문제를 해결하기 위해 바운드 와일드카드 타입(bounded wildcard type)을 이용할 수 있습니다.

Collection<? super E>로 표현하며, 이는 "E의 슈퍼 타입 요소를 가진 Collection"이라는 의미를 가집니다.

#08 와일드 카드 타입 popAll 메서드


아래와 같이 Collection<? super Number>는 Number의 슈퍼 클래스인 Object타입 요소를 가질 수 있습니다.

#09 바운드 와일드카드 타입




PECS


유연성을 극대화하려면 상황에 따라 적절한 와일드카드 타입을 이용해야 하는데, 이때 PESC를 따르는 게 좋습니다.


PECS : producer(생산자)-extends, consumer(소비자)-super

매개 변수 타입이 T 생산자를 나타내면 <? extends T>, T 소비자를 나타내면 <? super T>를 이용하면 됩니다.

위에서 본 pushAll 메서드는 Stack에서 이용하는 E 인스턴스를 생산하므로, Iterable<? extends E>.

popAll 메서드는 Stack으로부터 E 인스턴스를 소비하므로 Collection<? super E>입니다.




매거진의 이전글 제네릭(Generics)
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari