• 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());
}
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 +
'}';
}
}
ScheduledFuture는 Comparable을 직접 구현하지 않았지만, 그 상위 타입 (Delayed)이 구현하고 있다.
구체화 된것은 추상화 된것으로 일반적으로 가능하다.
// T 생산자 매개변수에 와일드카드 타입 적용 (184쪽)
public class Chooser<T> {
private final List<T> choiceList;
private final Random rnd = new Random();
// 코드 31-5 T 생산자 매개변수에 와일드카드 타입 적용 (184쪽)
public Chooser(Collection<? extends T> choices) {
choiceList = new ArrayList<>(choices);
}
public T choose() {
return choiceList.get(rnd.nextInt(choiceList.size()));
}
public static void main(String[] args) {
List<Integer> intList = List.of(1, 2, 3, 4, 5, 6);
Chooser<Number> chooser = new Chooser<>(intList);
for (int i = 0; i < 10; i++) {
Number choice = chooser.choose();
System.out.println(choice);
}
}
}
메서드 선언에 타입 매개변수가 한 번만 나오면 와일드카드로 대체하라.
한정적 타입이라면 한정적 와일드카드로
비한정적 타입이라면 비한정적 와일드카드로
public static void swap**(List<?>** list, int i, int j)
주의!
비한정적 와일드카드(?)로 정의한 타입에는 null을 제외한 아무것도 넣을 수 없다.
// 와일드카드 타입을 실제 타입으로 바꿔주는 private 도우미 메서드 (189쪽)
public class Swap {
public static <E> void swap(List<E> list, int i, int j) {
// public static void swap(List<?> list, int i, int j) {
list.set(i, list.set(j, list.get(i)));
// swapHelper(list, i, j);
}
// 와일드카드 타입을 실제 타입으로 바꿔주는 private 도우미 메서드
// private static <E> void swapHelper(List<E> list, int i, int j) {
// list.set(i, list.set(j, list.get(i)));
// }
public static void main(String[] args) {
// 첫 번째와 마지막 인수를 스왑한 후 결과 리스트를 출력한다.
List<String> argList = Arrays.asList(args);
swap(argList, 0, argList.size() - 1);
System.out.println(argList);
}
}
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)