Effective Java 2nd edition 을 요즘 보고 있는데, Java generics 에 관하여 좋은 글인 거 같아서 따로 복습도 할 겸 포스팅을 하게 되었다.
PECS 란 무엇인가 하면, Producer Extends, Consumer Super 라는 단어의 Initial 을 따서 붙인 것이다.
쉽게 설명을 하자면, 뭔가를 생산하는 일을 하면, 상속을 받고, 뭔가를 소비하게 되면 상속해 주는 것이다.
무슨 말인고 하니, Effective Java 2nd Edition 의 예를 들어보면,
Stack 의 일반화된 method 인 pushAll 을 보자.
// 뭔가 부족한 pushAll method - parameterized types E 를 사용하여 구현 public void pushAll(Iterable<E> src) { for (E e : src) push(e); } |
왜냐하면, parameterized types 는 invariant 하기 때문이다. invariant 하다는 것이 무슨 뜻이냐면,
두개의 구분된 Type1, Type2 가 있는데, List<Type1> 은 List<Type2> 의 supertype 도 아니고, subtype 도 아니라는 말이다.
그러므로 아래와 같은 코드에서는 compile time 오류가 발생하게 된다.
왜냐하면, Stack<Number> 와 Iterable<Integer> 는 서로 invariant 하기 때문이다.
// 위의 method 는 아래와 같은 상황에서 compile error 를 보고하게 한다. Stack<Number> numberStack = new Stack<Number>(); Iterable<Integer> integers = ...; numberStack.pushAll(integers); |
그래서 위와 같은 compile 에러를 고치기 위해서는 아래와 같이 bounded wildcard type 을 사용하여,
아래와 같이 작성해야 올바른 코드가 되고, type safe 한 프로그램이 된다.
// 개선된 pushAll method - parameter 의 wildcard type 은 E producer 로서 역할을 한다. public void pushAll(Iterable<? extends E> src) { for (E e : src) push(e); } |
그래서 위의 method 의 입력 parameter, src 는 E 의 Iterable 이 되면 안되고,
E 의 subtype 인 어떤 Iterable 이 되어야 한다는 것이다.
그리고 입력 paramter 인 src 는 Stack 클래스의 pushAll 의 자료를 공급하는 것(producer) 이기 때문에,
extends 가 사용됨을 알 수 있다. PE (producer-extends)
Stack 클래스의 popAll 이라는 일반화된 method 를 살펴보자.
// 뭔가 부족한 popAll method, parameterized type E 를 사용하여 구현되어 있다. public void popAll(Collection<E> dst) { while (!isEmpty()) dst.add(pop()); } |
위의 method 도 아래와 같은 상황에서 compile time 에러가 발생한다.
왜냐하면, Collection<Object> 는 Collection<Number> 의 subtype 이 아니기 때문이다.
Stack<Number> numberStack = new Stack<Number>(); Collection<Object> objects = ... ; numberStack.popAll(objects); |
그래서 아래와 같이 popAll method 의 입력 parameter 인 dst 는 E 의 supertype 인 어떤 Collection 이라고 명시해 주면 된다.
// wildcard type 은 E consumer 로서 역할 을 한다. public void popAll(Collection<? super E> dst) { while (!isEmpty()) dst.add(pop()); } |
여기서 입력 parameter 인 dst 는 Stack 클래스의 popAll 의 자료를 소비하는 것 (consumer) 이기 때문에,
super 가 사용됨을 알 수 있다. CS (consumer-super)
결론적으로, Java 언어에서 PECS 라는 것은 producer-extends, consumer-super 를 상징한다.
참고자료: Effective Java 2nd Edition, Joshua Bloch, Item 28
'Programming > Java' 카테고리의 다른 글
Java byte code 에 관하여 (0) | 2012.11.27 |
---|---|
Apache Ant 로 Runnable JAR 파일 만들기 (0) | 2012.11.27 |
Eclipse (이클립스) 에서 Java compiler 설정 (0) | 2012.11.27 |
Java Map 을 선언과 동시에 초기화 하기 (0) | 2012.11.27 |
Bounded wildcard type vs Bounded type parameter (0) | 2012.11.27 |