JVM/Java
[Java] 자바 제네릭 불공변 / 공변 / 반공변 처음 들어봅니다.
Hyo Kim
2022. 4. 22. 23:19
728x90
반응형
😀 서론
List<String>
List<E>
List<? extends E>
List<? super E>
당연하게 사용했던 자바의 제네릭은 여러 형태가 있다.
각각의 특징이 있고, 그 특징을 설명하는 용어를 알게 되었고, 정리해보려고 한다.
😗 본론
제목에 나와있는 3가지 특징을 한 번 정리하고 시작하겠습니다.
불공변 or 무공변 (Invariant) | List<String>은 List<Object>의 하위타입이 아니다. |
공변 (Covariant) | String 이 Object의 서브타입이면, List<String>은 List<? extend Object> 의 서브타입이다. |
반공변 (Contravariant) | String 이 Object의 서브타입이면, List<Object>은 List<? super String> 의 서브타입이다. |
불공변
List<Integer>와 List<Number> 는 서로 다르다.
제네릭은 기본적으로 불공변입니다.
그렇기 때문에 아래와 같이 코드를 작성할 시 우리는 오류 메시지를 확인하게 됩니다.
public class Stack {
...
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> numberStack = new Stack<>();
Iterable<Integer> integers = ...;
numberStack.pushAll(integers); // Error 발생
Stack<Number> numberStack = new Stack<>();
Collection<Object> objects = ...;
numberStack.popAll(objects); // Error 발생
공변
어떠한 T 타입의 공변성을 허용하려면 <? extend T>를 사용한다.
public void pushAll(Iterable<? extends E> src) {
for (E e : src)
push(e);
}
Stack<Number> numberStack = new Stack<>();
Iterable<Integer> integers = ...;
numberStack.pushAll(integers); // 깔끔한 컴파일
반공변
어떠한 T 타입의 반공변성을 허용하려면 <? super T>를 사용한다.
public void popAll(Collection<? super E> dst) {
while (!isEmpty())
dst.add(pop());
}
Stack<Number> numberStack = new Stack<>();
Collection<Object> objects = ...;
numberStack.popAll(objects); // 깔끔한 컴파일
공변 / 반공변은 왜 쓸까?
위 코드만 보더라도 제네릭을 더욱 유연하게 사용할 수 있게 해주는 걸 확인할 수 있습니다.
기본 제네릭 만으로는 하나의 타입밖에 표현할 수가 없고, 이는 리스코프 치환 원칙에도 어긋나게 됩니다.
언제 어떤걸 사용해야 할까?
펙스 (PECS) : producer-extends, consumer-super
위 공식을 외우게 되면, 어떤 와일드카드 타입을 써야 하는지 기억하는 데 도움이 될 것입니다.
즉, 생산자(producer)는 extends 를 사용하고,
소비자(consumer)는 super를 사용하면 됩니다.
반대로 사용할 경우 어차피 컴파일에서 에러를 잡아줍니다.
주의할 점
한정적 와일드카드는 반환 타입으로 설정하면 안 됩니다.
유연성을 높여주기커녕 클라이언트 코드에서도 와일드카드 타입을 사용해야 하기 때문입니다.
😆 결론
필요에 따라서 간혹 와일드카드를 사용하곤 했었는데 이러한 용어가 있다는 것을 알게 되어서
복습한다는 느낌으로 정리를 하면서 왜 나오게 되었는지도 알 수 있게 되어서 흥미로웠습니다.
이 내용은 이펙티브 자바3판 - 아이템 31 "한정적 와일드카드를 사용해 API 유연성을 높여라" 내용을 인용합니다.
728x90
반응형