아이템 31. 한정적 와일드카드를 사용해 API 유연성을 높이라

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>를 사용 -메서드 선언에 타입 매개변수가 한 번만 나오면 와일드 카드로 대체할것

아이템 32. 제네릭과 가변인수를 함께 쓸 때는 신중하라

가변인수 메서드를 호출하면 가변인수를 담기위한 배열이 자동으로 하나 만들어짐 제네릭과 가변인수를 혼용하면 타입 안정성이 깨짐 따라서 제네릭 varargs 배열 매개변수에 값을 저장하는 것은 안전하지 않음

@SafeVarargs

메서드 선언에 타입 매개변수가 한번만 나오면 와일드카드로 대체할 것