
List<Type1>은 List<Type2>의 하위 타입도 상위 타입도 아니다.List<String>은 List<Object>의 하위 타입이 아니다.public class Stack {
    public void pushAll(Iterable<E> src) {
        for (E e : src) {
            push(e);
        }
    }
}
Stack<Number>로 선언한 후 pushAll(intVal)을 호출하면(여기서 intVal은 Integer 타입이다) 논리적으로는 잘 동작해야 할 것 같지만 그렇지 않다.public class Stack {
    public void pushAll(Iterable<? extends E> src) {
        for (E e : src) {
            push(e);
        }
    }
}
Iterable<? extends E>가 정확히 이런 뜻을 의미한다. 여기서 하위 타입은 자기 자신도 포함한다.public class Stack {
    public void popAll(Collection<E> dst) {
        while (!isEmpty()) {
            dst.add(pop());
        }
    }
}
Collection<Object>Collection<Number>의 하위 타입이 아니다. 라는 오류가 발생한다(앞의 예시와 비슷하다).public class Stack {
    public void popAll(Collection<? super E> dst) {
        while (!isEmpty()) {
            dst.add(pop());
        }
    }
}
<? extends T>를 사용하고, 소비자라면 <? super T>를 사용하도록 한다.겟풋 원칙(Get and Put Principle)으로 불리기도 한다.public class Item31 {
    public Chooser(Collection<? extends T> choices);
}
Chooser<Number>의 생성자에 List<Integer>를 넘길 수 있다.public class Item31 {
    public static <E> Set<E> union(Set<E> s1, Set<E> s2);
}
public class Item31 {
    public static <E> Set<E> union(Set<? extends E> s1, Set<? extends E> s2);
}
Set<E>인 것에 주의해야 한다.public class Item31 {
    void add(int value) {
        // ...
    }
    add(10);
    class Set<T> {
        // ...
    }
    Set<Integer> = // ...;
}
public class Item31 {
    public static <E extends Comparable<E>> E max(List<E> list);
    public static <E extends Comparable<? super E>> E max(List<? extends E> list); // 와일드카드를 이용해서 다듬은 메서드
}
Comparable<E>는 E 인스턴스를 소비한 뒤, 선후 관계를 뜻하는 정수를 생산한다.Comparable<E>보다는 Comparable<? super E>를 사용하는 편이 낫다.Comparable(혹은 Comparator)을 직접 구현하지 않고, 직접 구현한 다른 타입을 확장한 타입을 지원하기 위해서는 와일드카드가 필요하다.
List<ScheduledFuture<?>> scheduledFutures = ...;를 처리할 수 없다.List<ScheduledFuture<?>>를 거부한다. 아래의 상속 관계와 함께 생각해보자.public interface Comparable<E>;
public interface Delayed extends Comparable<Delayed>;
public interface ScheduledFuture<V> extends Delayedm Future<V>;
public class Item31 {
    public static <E> void swap(List<E> list, int i, int j);
    public static void swap(List<?> list, int i, int j);
}
List<?>라는 타입의 리스트에는 null 외에는 어떤 값도 넣을 수 없다. 이 경우, 도우미 메서드를 따로 작성하여 활용하는 방법으로 사용할 수 있다. 이때, 실제 타입을 알아내려면 이 도우미 메서드는 제네릭이어야 한다.public class Item31 {
    public static <E> void swap(List<E> list, int i, int j) {
        swapHelper(list, i, j);
    }
    private static <E> void swapHelper(List<E> list, int i, int j) {
        list.set(i, list.set(j, list.get(i)));
    }
}
List<E>임을 알고 있다.