핵심 정리 1: Chooser와 Union API 개선

• PECS: Producer-Extends, Consumer-Super

• Producer-Extends

• Object의 컬렉션 Number나 Integer를 넣을 수 있다.

• Number의 컬렉션에 Integer를 넣을 수 있다.

     // 코드 31-2 E 생산자(producer) 매개변수에 와일드카드 타입 적용 (182쪽)
     // Number 의 하위 타입의 Iterable 
    **public void pushAll(Iterable<? extends E> src)** {
        for (E e : src)
            push(e);
    }
    
    // 제네릭 Stack을 사용하는 맛보기 프로그램
    public static void main(String[] args) {
        Stack<Number> numberStack = new Stack<>();
        Iterable<Integer> integers = Arrays.asList(3, 1, 4, 1, 5, 9);
        numberStack.pushAll(integers);

        Iterable<Double> doubles = Arrays.asList(3.1, 1.0, 4.0, 1.0, 5.0, 9.0);
        numberStack.pushAll(doubles);

        Collection<Object> objects = new ArrayList<>();
        numberStack.popAll(objects);

        System.out.println(objects);
    }

• Consumer-Super

• Integer의 컬렉션의 객체를 꺼내서 Number의 컬렉션에 담을 수 있다.

• Number나 Integer의 컬렉션의 객체를 꺼내서 Object의 컬렉션에 담 을 수 있다

    // 코드 31-4 E 소비자(consumer) 매개변수에 와일드카드 타입 적용 (183쪽)
    **public void popAll(Collection<? super E> dst)** {
        while (!isEmpty())
            dst.add(pop());
    }

핵심 정리 2: Comparator와 Comparable은 소비자

Comparable을 직접 구현하지 않고, 직접 구현한 다른 타입을 확장한 타입을 지 원하려면 와일드카드가 필요하다

// 와일드카드 타입을 사용해 재귀적 타입 한정을 다듬었다. (187쪽)
public class RecursiveTypeBound {
    public static <E extends Comparable<? super E>> E max(List<? extends E> list) {
        if (list.isEmpty())
            throw new IllegalArgumentException("빈 리스트");

        E result = null;
        for (E e : list)
            if (result == null || e.compareTo(result) > 0)
                result = e;

        return result;
    }

    public static void main(String[] args) {
        List<IntegerBox> list = new ArrayList<>();
        list.add(new IntegerBox(10, "keesun"));
        list.add(new IntegerBox(2, "whiteship"));

        System.out.println(max(list));
    }
}

===

public class Box<T extends Comparable<T>> implements Comparable<Box<T>> {

    protected T value;

    public Box(T value) {
        this.value = value;
    }

    public void change(T value) {
        this.value = value;
    }

    @SuppressWarnings("unchecked")
    @Override
    public int compareTo(Box anotherBox) {
        return this.value.compareTo((T)anotherBox.value);
    }

    @Override
    public String toString() {
        return "Box{" +
                "value=" + value +
                '}';
    }
}

===

public class IntegerBox extends Box<Integer> {

    private final String message;

    public IntegerBox(int value, String message) {
        super(value);
        this.message = message;
    }

    @Override
    public String toString() {
        return "IntegerBox{" +
                "message='" + message + '\\'' +
                ", value=" + value +
                '}';
    }
}

핵심 정리 3: 와일드카드 활용 팁

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

주의!

완벽 공략 44. 타입 추론

Type Inference

• 타입을 추론하는 컴파일러의 기능

    public static void main(String[] args) {
        **ArrayList<Box<Integer>> listOfIntegerBoxes = new ArrayList<>();**
        BoxExample.addBox(10, listOfIntegerBoxes);
        BoxExample.addBox(20, listOfIntegerBoxes);
        BoxExample.addBox(30, listOfIntegerBoxes);
        BoxExample.outputBoxes(listOfIntegerBoxes);

    public static void main(String[] args) {
        ArrayList<Box<Integer>> listOfIntegerBoxes = new ArrayList<>();
        BoxExample.addBox(10, listOfIntegerBoxes);
        BoxExample.addBox(20, listOfIntegerBoxes);
        BoxExample.addBox(30, listOfIntegerBoxes);
        BoxExample.outputBoxes(listOfIntegerBoxes);

        // Target Type
        List<String> stringlist = Collections.emptyList();
        List<Integer> integerlist = Collections.emptyList();
        BoxExample.processStringList(Collections.emptyList());
    }
    }
}

• 모든 인자의 가장 구체적인 공통 타입 (most specific type)