public class Stack<E> {
private List<E> elements;
private int size = 0;
public Stack() {
this.elements = new ArrayList<>();
}
public static void main(String[] args) {
Stack<Number> stack = new Stack<>();
Iterable<Integer> integers = Arrays.asList(1);
stack.pushAll(integers);
}
public void push(E o) {
elements.add(o);
size++;
}
public <E> E pop() {
if (size == 0) {
throw new EmptyStackException();
}
E element = (E)elements.get(size);
elements.remove(size--);
return element;
}
public void pushAll(Iterable<E> src) {
for (E e : src) {
push(e);
}
}
public boolean isEmpty() {
return elements.size() == 0;
}
}
스택 코드를 봤을 때, 논리적으로는 Number를 담을 수 있는 스택이 Integer도 담을 수 있어야 할 것 같지만 제네릭은 불공변이기 때문에 Integer가 Number의 하위타입인 것은 전혀 상관이 없음
유연한 스택을 만들기 위해 한정적 와일드 타입을 쓸 수 있음
한정적 와일드 카드 타입 원소의 생산자나 소비자용 입력 매개변수 일 때 원소가 생산자와 소비자 역할을 동시에 사용하지 말 것, 이는 타입을 정확히 지정해야하는 상황을 뜻함 유연성을 극대화 하기 위해서 사용
PECS(Producer-Extends, Consumer-Super) -매개변수화 타입 T가 생산자라면 <? extends T>를 사용하고, 소비자라면 <? super T>를 사용하라.
주의 점 -반환 타입에는 한정적 와일드카드 타입을 사용하면 안됨 -사용하는 순간 클라이언트 코드에서도 와일드 카드 타입을 신경써야 하기 때문에 API에 문제가 있음
정리 -PECS(Producer-Extends, Consumer-Super) -반환 타입에는 한정적 와일드카드 타입을 사용하면 안됨 사용하는 순간 클라이언트 코드에서도 와일드 카드 타입을 신경써야 하기 때문에 API에 문제가 있음 -Comparable보다는 Comparable<? super E>를 사용 -Comparator보다는 Comparator<? super E>를 사용 -메서드 선언에 타입 매개변수가 한 번만 나오면 와일드 카드로 대체할것
가변인수 메서드를 호출하면 가변인수를 담기위한 배열이 자동으로 하나 만들어짐 제네릭과 가변인수를 혼용하면 타입 안정성이 깨짐 따라서 제네릭 varargs 배열 매개변수에 값을 저장하는 것은 안전하지 않음
@SafeVarargs
메서드 선언에 타입 매개변수가 한번만 나오면 와일드카드로 대체할 것