Chapter 5 μ λ€λ¦
Item 26 λ‘ νμ μ μ¬μ©νμ§ λ§λΌ
μ λ€λ¦ νμ μ κ°κ° μΌλ ¨μ λ§€κ°λ³μν νμ (parameterized type) μ μ μ νλ€.
μ λ€λ¦ νμ
μ νλ μ μνλ©΄ κ·Έμ λΈλ¦° λ‘ νμ
 (row type) λ ν¨κ» μ μλλ€.
μ΄λ μ λ€λ¦ νμ
μμ νμ
 λ§€κ°λ³μλ₯Ό μ ν μ¬μ©νμ§ μλ λλ₯Ό λ§νλ€.
λ‘ νμ
μ νμ
 μ μΈμμ μ λ€λ¦ νμ
 μ λ³΄κ° μ λΆ μ§μμ§ κ²μ²λΌ λμνλλ°,
μ λ€λ¦μ΄ λλνκΈ°μ μ μ  μ½λμ νΈνλλλ‘ νκΈ° μν κΆμ¬μ§μ±
μ΄λ€.
μ λ€λ¦μμ λ‘ νμ
μ μ λ€λ¦μ΄ μ겨주λ μμ μ±κ³Ό ννλ ₯μ λͺ¨λ μΌκ² λκΈ° λλ¬Έμ μ¬μ©μ΄ μ§μλλ
μ λ€λ¦ λ±μ₯ μ΄μ μ μ¬μ©νλ μ½λλ€μ΄ μ λ€λ¦μ μ§μνμ§ μκΈ° λλ¬Έμ
λ‘ νμ
μ μ§μνκ²λ λ§μ΄κ·Έλ μ΄μ
 νΈνμ±μ μν΄ λ‘ νμ
μ μ§μνκ³ 
μ λ€λ¦μ ꡬνμλ μκ±° (erasure) λ°©μμ μ¬μ©νκΈ°λ‘ νλ€.
Item 27 λΉκ²μ¬ κ²½κ³ λ₯Ό μ κ±°νλΌ
μ λ€λ¦ μ¬μ©μ λ§μ μ»΄νμΌλ¬ κ²½κ³ λ₯Ό μ κ±°ν΄μΌ νλ€.
// Runtime Error
Set<Lark> exaltation = new HashSet();
// Success
Set<Lark> exaltation = new HashSet<>();
JDK 7 λΆν° μ§μνλ λ€μ΄μλͺ¬λ μ°μ°μ (<>) λ₯Ό μ¬μ©νμ¬ νμ
 μΆλ‘ μ μ¬μ©νμ¬ λΉκ²μ¬ κ²½κ³ λ₯Ό μ κ±°νμ.
λͺ¨λ  λΉ κ²μ¬ κ²½κ³ λ₯Ό μ κ±°νλ©΄ νμ
 μμ μ±μ΄ 보μ₯λλ©° λ° νμμμ ClassCaseException μ΄ λ°μν  μΌμ΄ μλ€.
κ²½κ³ λ₯Ό μ κ±°ν  μ μμ§λ§ νμ
μ΄ μμ νλ€κ³  νμ  νλ€λ©΄ @SuppressWarnings("unchecked") Annotation μ μ¬μ©νμ¬ κ²½κ³ λ₯Ό μ¨κΈ°μ.
@SuppressWarnings("unchecked") Annotation μ μ¬μ©ν λλ κ·Έ κ²½κ³ λ₯Ό 무μν΄λ μμ ν κ·Όκ±°λ₯Ό μ£ΌμμΌλ‘ λͺ
μν΄μ€μΌ νλ€.
Item 28 λ°°μ΄λ³΄λ€λ 리μ€νΈλ₯Ό μ¬μ©νλΌ
μλ μ½λλ RuntimeException μ λ°ννλ€.
Object[] objAry = new Long[1];
// ArrayStoreException μ λ°ν
objAry[0] = "νμ
μ΄ λ¬λΌ λ£μ μ μλ€.";
μ΄λ λ°°μ΄μ΄ 곡λ³νμ μ΄λΌ Long μ© μ μ₯μμ String μ λ£μμ μμ§λ§ μ»΄νμΌμμλ μμ μλ€.
// νΈνλμ§ μλ νμ
List<Object> = objList = new ArrayList<Long>();
objList.add("νμ
μ΄ λ¬λΌ λ£μ μ μλ€.");
μ μ½λλ μ»΄νμΌμμ μ€λ₯λ₯Ό κ²μ¦ ν μ μλ€.
λν λ°°μ΄μ μ€μ²΄ν (reify) λλ€.
μ΄λ λ°°μ΄μ λ°νμμλ μμ μ΄ λ΄κΈ°λ‘ ν μμμ νμ
μ μΈμ§νκ³  νμΈ νλ€. κ·Έλμ 곡λ³μμλ λΆκ΅¬νκ³  λ°νμμμ μλ‘ λ€λ₯Έ νμ
μ μ½μ
νμμλ ArrayStoreException μ΄ λ°μνλκ²μ΄λ€.
μ΄μ λ°λλ‘ μ λ€λ¦μ λ°νμμμλ λ°μ΄ν° νμ
μ΄ μκ±°κ° λλ Type Erasure νμμ΄ λ°μλλ€. μμνμ
μ μ»΄νμΌμμλ§ κ²μ¬νλ©° λ°νμμλ μ μ μλ€λ λ»μ΄λ€.
μ΄ Type Erasure λ μ λλ¦μ΄ μ§μλκΈ° μ μ λ κ±°μ μ½λμ μ λ€λ¦ νμ
μ μμ‘°λ‘κ² μ¬μ© κ°λ₯νλλ‘ νλ μΌμ’
μ 맀컀λμ¦μΌλ‘ μνμ ν΄μ€λ€.
μ¬μ©λΆκ° μ λ€λ¦ μ ν
- μ λ€λ¦ νμ
 :: 
new List<E>[] - λ§€κ°λ³μν νμ
 :: 
new List<String>[] - νμ
 λ§€κ°λ³μ :: 
new E[] 
μ μΈκ°μ§ μ νμ νμ μ΄ μμ νμ§ μκΈ° λλ¬Έμ μ λ€λ¦ λ°°μ΄μ λ§λ€ μ μλ€.
μ΄λ E List<E> List<String> μ κ°μ νμ
μ μ€μ²΄ν λΆκ° νμ
 (non-reifiable type) μ΄λΌκ³  νλλ° μ€μ²΄ν λμ§ μμμ λ°νμμ μ»΄νμΌ ν λλ³΄λ€ μ λ³΄λμ΄ μ κ² κ°μ§λ νμ
 μ λ§νλ€.
μκ±° 맀컀λμ¦ λλ¬Έμ λ§€κ°λ³μν νμ
 κ°μ΄λ° μ€μ²΄ν λ μ μλ νμ
μ List<?> μ Map<?, ?> κ°μ λΉ νμ  μμΌλμΉ΄λ νμ
 λΏμ΄λ€.
λ°°μ΄μ λΉνμ μ  μμΌλμΉ΄λ νμ
μΌλ‘ λ§λ€μ μμ§λ§ μ μ©νκ² μΈ μΌμ΄ κ±°μ μλ€.
μ€μ²΄ν λΆκ° νμ
μ μ¬μ©ν λλ μμ λ κ°λ³μΈμ(varags) λΌλ μλ―Έλ‘ @SafeVarargs Annotation μ μ¬μ©νμ¬ λ체 κ°λ₯νλ€.
μμ±μμμ 컬λ μ μ λ°μ Chooser ν΄λμ€ λ¦¬νν λ§
public class Chooser {
  private final Object[] choiceArray;
  public Chooser(Collection choices) {
    choiceArray = choices.toArray();
  }
  public Object choose() {
    Random rnd = ThreadLocalRandom.current();
    return choiceArray[rnd.nextInt(choiceArray.length)];
  }
}
choose() λ©μλλ₯Ό νΈμΆ ν λλ§λ€ λ°νλ Objectλ₯Ό μνλ νμ
μΌλ‘ ν λ°ν ν΄μΌ νκΈ° λλ¬Έμ νμ
μ΄ λ€λ₯Έ μμκ° λ€μ΄μμΌλ©΄ ν λ³ν μ€λ₯κ° λλ€
λλ¬Έμ ν΄λΉ ν΄λμ€λ₯Ό μ λ€λ¦μΌλ‘ λ³ννλ€.
public class Chooser<T> {
  private final T[] choiceArray;
  public Chooser(Collection<T> choices) {
    choiceArray = choiceArray.toArray();
  }
  // choose λ©μλλ κ·Έλλ‘
}
Object[] κ° T[] μΌλ‘ λ³ν λμ§ μκΈ° λλ¬Έμ λͺ
μμ μΌλ‘ μΊμ€ν
 ν΄μ€λ€.
public class Chooser<T> {
  private final T[] choiceArray;
  public Chooser(Collection<T> choices) {
    choiceArray = (T[]) choiceArray.toArray();
  }
  // choose λ©μλλ κ·Έλλ‘
}
T[] κ° λ¬΄μ¨ νμ
μΈμ§ μ μ μμΌλ ν λ³νμ΄ λ°νμμ μμ ν¨μ 보μ₯ν μ μλ€λ κ²½κ³ κ° λ¬λ€.
λΉκ²μ¬ ν λ³ν κ²½κ³ μ΄κΈ° λλ¬Έμ λ°°μ΄ λμ 리μ€νΈλ₯Ό μ¬μ©νλ€.
public class Chooser<T> {
  private final List<T> choiceList;
  public Chooser(Collection<T> choices) {
    choiceList = new ArrayList<>(choices);
  }
  public T choose() {
    Random rnd = ThreadLocalRandom.current();
    return choiceList.get(rnd.nextInt(choiceList.size()));
  }
}
μ½λλμ μ‘°κΈλ λμκ³  μλ§λ μ‘°κΈλ λ리μ§λ§,
λ°νμμ ClassCastException μ΄ λ°μλ  λ¦¬μ€ν¬κ° μ€μλ€.
ν΅μ¬ μ 리
λ°°μ΄μ κ³΅λ³ μ΄κ³  μ€μ²΄ν λλ λ°λ©΄,
μ λ€λ¦μ λΆκ³΅λ³ μ΄κ³  νμ
 μ λ³΄κ° μκ±° λλ€.
λ°°μ΄μ λ°νμμλ νμ
μ΄ μμ  νμ§λ§ μ»΄νμΌ νμμλ μμ νμ§ μλ€.
 μ λ€λ¦μ μ΄μ λ°λ μ¬μ κ·Έ λμ μμ΄ μ°κΈ°λ μ½μ§ μλ€.
λμ μμ΄ μ°λ€ μ»΄νμΌ μ€λ₯λ κ²½κ³ λ₯Ό λ§λλ©΄ κ°μ₯ λ¨Όμ  λ°°μ΄μ 리μ€νΈλ‘ λ체νλ λ°©λ²μ μ μ© ν΄λ³΄μ.
Item 29 μ΄μμ΄λ©΄ μ λ€λ¦ νμ μΌλ‘ λ§λ€λΌ
ν΄λΌμ΄μΈνΈμμλ μ§μ  ν λ³νν΄μΌ νλ νμ λ³΄λ€ μ λ€λ¦ νμ μ΄ λ μμ νκ³ μ°κΈ° νΈνλ€.
μλ‘μ΄ νμ μ μ€κ³ν λλ ν λ³ν μμ΄λ μ¬μ©ν μ μλλ‘ μ λ€λ¦ νμ μΌλ‘ λ§λ€μ΄μΌ ν κ²½μ°κ° λ§λ€.
λ€μμ Stack ν΄λμ€λ μ λ€λ¦ νμ
μΌλ‘ 리νν λ§ νλ κ³Όμ μ΄λ€.
public class Stack {
  private Object[] elements;
  private int size = 0;
  private static final int DEFAULT_INITIAL_CAPACITY = 16;
  public Stack() {
    elements = new Object[DEFAULT_INITAL_CAPACITY];
  }
  public void push(Object e) {
    ensureCapacity();
    elements[size++] = e;
  }
  public Object pop() {
    if (size == 0)
      throw new EmptyStackException();
    Object result = elements[--size];
    // μ¬μ©μ΄ λλ μ°Έμ‘°λ₯Ό ν΄μ 
    elements[size] = null;
    return result;
  }
  public boolean isEmpty() {
    return size == 0;
  }
  private void ensureCapacity() {
    if (elements.length == size)
      elements = Arrays.copyOf(elements, 2 * size + 1);
  }
}
Object λ₯Ό μ λ€λ¦ νμ
μΌλ‘ λ³κ²½νλ€.
public class Stack<E> {
  private E[] elements;
  private int size = 0;
  private static final int DEFAULT_INITAL_CAPACITY = 16;
  public Stack() {
    elements = new E(DEFAULT_INITAL_CAPACITY);
  }
  public void push(E e) {
    ensureCapacity();
    elements[size++] = e;
  }
  public E pop() {
    if (size == 0)
      throw new EmptyStackException();
    E result = elements[--size];
    // μ¬μ©μ΄ λλ μ°Έμ‘° ν΄μ 
    elements[size] = null;
    return result;
  }
}
μλμ κ°μ E λ μ€μ²΄ν λΆκ° νμ
μΌλ‘ λ°°μ΄μ λ§λ€μ μμ΄ μλμ κ°μ μλ¬λ₯Ό λ±λλ€.
Stack.java:8: generic array creation
  elements = new E[DEFAULT_INITIAL_CAPACITY];
μ΄ κ²½κ³ λ λΉκ²μ¬ νλ³νμ΄ νλ‘κ·Έλ¨μ μμ μ±μ ν΄μΉ μ μλ€λ μλ―Έμ΄λ―λ‘ μ€μ€λ‘ νμΈν΄μΌ νλ€.
- λ°°μ΄μ 
elementsλprivateνλμ μ μ₯λλ€. - Client λ‘ λ°νλκ±°λ λ€λ₯Έ λ©μλμ μ λ¬λλ μΌμ΄ μ ν μλ€.
 push()λ©μλλ₯Ό ν΅ν΄ λ°°μ΄μ μ μ₯λλ μμμ νμ μ νμ E λ€.
νμ μ 3κ°μ§ 쑰건μ λ§μ‘±νλ―λ‘ μ΄ μ½λμ λΉκ²μ¬ νλ³νμ μμ νλ€.
μλμ κ°μ΄ μ λ€λ¦ λ°°μ΄ μμ±μ κΈμ§νλ μ μ½μ μ°ννλ λ°©λ²μΌλ‘
 Object λ°°μ΄μ μμ±ν λ€μ μ λ€λ¦ λ°°μ΄λ‘ νλ³ν νλ λ°©λ²μ΄ μλ€.
νμ§λ§ μ΄λ μ€λ₯λμ  κ²½κ³  λ₯Ό λ΄λ³΄λΈλ€.
μλ μ½λμ κ°μ΄ μμ±μ λ©μλλ₯Ό @SuppressWarnings("unchecked") μ λν
μ΄μ
μΌλ‘ ν΄λΉ κ²½κ³ λ₯Ό μ¨κΈ΄λ€.
λ°°μ΄ elements μ push(E) λ‘ λμ΄μ¨ μΈμ€ν΄μ€ E λ§ λ΄λλ€.
@SuppressWarnings("unchecked")
public Stack() {
  elements = (E[]) new Object[DEFAULT_INITAL_CAPACITY];
}
μ μ½λλ νμ
μ μμ μ±μ 보μ₯νμ§λ§ μ΄ λ°°μ΄μ λ°νμ
μ E[] κ° μλ Object[] μ΄λ€.
μλμ κ°μ΄ λ°°μ΄ κ°μ²΄ elements νλ³ν ν  μ μλ€λ μλ¬κ° λ¬λ€.
Stack.java:19: incompatible types found: Object, required: E
  E result = elements[--size];
λ°°μ΄μ΄ λ°νν μμλ₯Ό E λ‘ νλ³ν νλ©΄ μ€λ₯λμ  κ²½κ³ κ° λ¬λ€.
Stack.java:19: warning: [unchecked] unchecked cast found: Object, required: E
  E result = (E) elements[--size];
μ μ½λμμμ κ²½κ³  E λ μ€μ²΄ν λΆκ° νμ
μ΄λ―λ‘ λ°νμμ μ΄λ£¨μ΄μ§λ νλ³νμ΄ μμ νμ§ μ¦λͺ
ν  λ°©λ²μ΄ μλ€.
νμ§λ§ push() λ©μλμμλ E νμ
λ§ νμ©νλ―λ‘ μ νλ³νμ μμ νλ€.
νλ³νμ΄ μμ νλ€ μκ°μ΄ λ€λ©΄ λΉκ²μ¬ κ²½κ³ λ₯Ό μ¨κΈ΄λ€.
public E pop() {
  if (size == 0)
    throw new EmptyStackException();
  @SuppressWarnings("unchecked")
  E result = (E) elements[--size];
  // μ¬μ©μ΄ λλ μ°Έμ‘°λ₯Ό ν΄μ 
  elements[size] = null;
  return result;
}
Item 28 μμμ λ°°μ΄λ³΄λ€λ 리μ€νΈλ₯Ό μ°μ νλΌλ μν©μ λ°λΌ λ€λ₯΄λ©°
μ λ€λ¦ νμ
 μμμ 리μ€νΈλ₯Ό μ¬μ©νλκ² νμ κ°λ₯νμ§λ λ μ’μ λ°©λ²μ΄ μλμλ μλ€.
μλ°κ° 리μ€νΈλ₯Ό κΈ°λ³Ένμ
μΌλ‘ μ κ³΅νμ§ μμΌλ―λ‘ ArrayList μ κ°μ μ λ€λ¦ νμ
λ κ²°κ΅μ κΈ°λ³Έ νμ
μΈ λ°°μ΄μ μ¬μ©ν΄ ꡬνν΄μΌ νλ κ²½μ°λ μλ€.
HashMap κ³Ό κ°μ μ λ€λ¦ νμ
μ μ±λ₯μ λμΌ λͺ©μ μΌλ‘ λ°°μ΄μ μ¬μ©νκΈ°λ νλ€.
μ λ€λ¦ νμ
μ νμ
 λ§€κ°λ³μμ μ΄λ ν μ μ½μ λκ³  μμ§λ μμ§λ§ κΈ°λ³Ένμ
μ μ¬μ©ν  μ μλ€.
κ°λ Ή Stack<int> Stack<double> μ λ§λλ €κ³  νλ©΄ μ»΄νμΌ μ€λ₯κ° λλ€.
μ΄λ μλ°μ κ·Όλͺ¬μ μΈ λ¬Έμ μ΄λ, λ°μ±λ κΈ°λ³Ένμ
μ μ¬μ©νμ¬ μ°νκ° κ°λ₯νλ€.
νΉμ νμ
 λ§€κ°λ³μμ μ μ½μ λμ΄ μ¬μ©νλ λ°©λ²λ μλ€. (νμ μ  νμ
 λ§€κ°λ³μ)
μλ₯Ό λ€λ©΄ java.util.concurrent.DelayQueue κ³Ό κ°μ΄ DelayQueue μμ κ³Ό DelayQueue μ μμλ₯Ό μ¬μ©νλ Delayed ν΄λμ€μμ ClassCastException κ±±μ  ν  νμ μμ΄ μ¬μ© κ°λ₯νλ€.
Item 30 μ΄μμ΄λ©΄ μ λ€λ¦ λ©μλλ‘ λ§λ€λΌ
ν΄λμ€μ λ§μ°¬κ°μ§λ‘ λ©μλλ μ λ€λ¦μΌλ‘ λ§λ€μ μλ€.
λ§€κ°λ³μν νμ
μ λ°λ μ μ  μ νΈλ¦¬ν° λ©μλλ μ λ€λ¦μΌλ‘ λνμ μΌλ‘ Collections μ μκ³ λ¦¬μ¦ λ©μλλ λͺ¨λ μ λ€λ¦ λ©μλμ΄λ€.
public static Set union(Set s1, Set s2) {
  Set result = new HashSet(s1);
  result.addAll(s2);
  return result;
}
μ μ½λλ μ»΄νμΌμ λμ§λ§ κ²½κ³ κ° λκ°κ° λ°μνλ€.
Union.java:5: warning: [unchecked] unchecked call to HashSet(Collection<? extends E>) as a member of raw type HashSet
  Set result = new HashSet(s1);
Union.java:6: warning: [unchecked] unchecked call to addAll(Collection<? extends E>) as a member of raw type Set
  result.addAll(s2);
μ κ²½κ³ λ λ©μλ νμ μ μμ μ±μ 보μ₯ν΄μΌ νλ€.
public static <E> Set<E> union(Set<E> s1, Set<E> s2) {
  Set<E> result = new HashSet<>();
  result.addAll(s2);
  return result;
}
λ¨μν μ λ€λ¦ λ©μλλΌλ©΄ μ μ½λμ λκ° μ λΉνλ€.
μ΄ λ©μλλ κ²½κ³  μμ΄ μ»΄νμΌ λλ©°, μμ νκ³  μ°κΈ°λ μ½λ€.
public static void main(String[] args) {
  Set<String> guys = Set.of("ν°", "λ", "ν΄λ¦¬");
  Set<String> stooges = Set.of("λ리", "λͺ¨μ", "컬리");
  Set<String> aflCio = union(guys, stooges);
  System.out.println(aflcio);
}
μ νλ‘κ·Έλ¨μ μ€νμμΌ°μλμ κ²°κ³Όλ μλμ κ°λ€.
[λͺ¨μ, ν°, ν΄λ¦¬, λ리, 컬리, λ]
νλ±ν¨μ λ μ
λ ₯κ°μ μμ μμ΄ κ·Έλλ‘ λ°ννλ νΉλ³ν ν¨μλ‘
μ΄λ₯Ό μ΄μ©ν μ λ€λ¦ μ±κΈν΄ λ°©μλ₯Ό λ§λ€λ©΄ μλμ μμμ κ°λ€.
public static UnaryOperator<Object> IDENTITY_FN = (t) -> t;
@SuppressWarning("unchecked")
public static <T> UnaryOperator<T> identityFunction() {
  return (UnaryOperator<T>) IDENTITY_FN
}
μ λΉκ²μ¬ κ²½κ³  μ λν
μ΄μ
μ T κ° μ΄λ€ νμ
μ΄λ  UnaryOperator<Object> λ UnaryOperator<T> κ° μλκΈ° λλ¬Έμ΄λ€ (νμ
 μκ±°)
νμ§λ§ νλ± ν¨μλ T κ° μ΄λ€ νμ
μ΄λ  μ
λ ₯ κ°μ κ·Έλλ‘ λ°ννκΈ° λλ¬Έμ UnaryOperator<T> λ₯Ό μ¬μ©ν΄λ μμ νλ€.
Item 31 νμ μ  μμΌλμΉ΄λλ₯Ό μ¬μ©ν΄ API μ μ°μ±μ λμ΄λΌ
λ§€κ°λ³μν νμ (Parameterized Types) μ λΆκ³΅λ³ (invariant) μ΄λ€.
μμΌλμΉ΄λ νμ
μ μ¬μ©νμ§ μμ pushAll() λ©μλλ κ²°ν¨μ΄ μλ€.
public void pushAll(Iterable<E> src) {
  for (E e : src) {
    push(e);
  }
}
Integer λ Number μ νμνμ
μ΄λ μ λμ ν΄μΌ νλ€. (리μ€μ½ν μΉν λ²μΉ)
Stack<Number> numberStack = new Stack();
Iterable<Integer> integers = ...;
numberStack.pushAll(integers);
νμ§λ§ μλμ κ°μ΄ μ€λ₯ λ©μΈμ§κ° λ¬λ€.
 λ§€κ°λ³μν νμ
μ΄ λΆκ³΅λ³μ΄κΈ° λλ¬Έ μ΄λ€.
StackTest.java:7: error: incompatible types: Iterable<Integer> cannot be converted to Iterable<Number>
  numberStack.pushAll(integers);
μ μλ¬λ₯Ό κ³ μΉκΈ° μν΄μ μλ°λ νμ μ  μμΌλ μΉ΄λ νμ
μ΄λΌλ νΉλ³ν λ§€κ°λ³μν νμ
μ μ§μ νλ€.
 pushAll() μ μ
λ ₯ λ§€κ°λ³μ νμ
μ E μ Iterable μ΄ μλλΌ E μ νμ νμ
μ Iterable μ΄μ¬μΌ νλ©° μμΌλ μΉ΄λμ νμ
μ Iterable<? extends E> μ΄ λμ΄μΌ νλ€.
μμ°μ (Producer) μ μν λ§€κ°λ³μν νμ μ μ μ©
public void pushAll(Iterable<? extends E> src) {
  for (E e : src) {
    push(e);
  }
}
popAll() λ©μλ λν μμΌλμΉ΄λμ λ―Έμ μ©μΌλ‘ μΈν΄ κ²°ν¨μ΄ μκΈ΄λ€.
Stack<Number> numberStack = new Stack<>();
Collection<Object> objects = ...;
numberStack.popAll(objects);
μ μ½λλ₯Ό μ»΄νμΌ νλ©΄ Collection<Object> λ Collction<Number> μ νμνμ
μ΄ μλλ€ λΌλ λ©μΈμ§μ ν¨κ» μ€λ₯κ° λ°μνλ€.
μ΄ κ²½μ°μλ νμ μ  μμΌλμΉ΄λ νμ
μ μ μ©νμ¬ ν΄κ²°νλ€.
popAll() μ μ
λ ₯ λ§€κ°λ³μ νμ
μ΄ E μ Collection μ΄ μλλΌ E μ μμ νμ
μ Collection μ΄μ¬μΌ νλ©° μμΌλ μΉ΄λμ νμ
μ Collection<? super E> κ° λμ΄μΌ νλ€.
μλΉμ (Consumer) λ§€κ°λ³μμ μμΌλμΉ΄λ νμ μ μ μ©
public void popAll(Collection<? super E> dst) {
  while(!isEmpty())
    dst.add(pop());
}
PECS
μμ κ°μ ν¨ν΄μ PECS (Producer Extends & Consumer Super) λΌκ³  νλ©° λ§€κ°λ³μλ₯Ό μ μ°μ±μκ² μμΌλμΉ΄λλ₯Ό μ¬μ©νκ²λ λμμ€λ€.
λ§€κ°λ³μν νμ
 T μμ° λ° μλΉμ λ§κ² νμ μ  μμΌλ μΉ΄λκ° λΆλ¦¬λλ€.
- μμ°μ : 
<? extends T> - μλΉμ : 
<? super T> 
Item 32 μ λ€λ¦κ³Ό κ°λ³μΈμλ₯Ό ν¨κ» μΈ λλ μ μ€νλΌ
μ€μ²΄ν λΆκ° νμ (non-reifiable type) μ λ°νμμλ μ»΄νμΌ νμλ³΄λ€ νμ κ΄λ ¨ μ 보λ₯Ό μ κ² λ΄κ³ μλ€.
λ©μλλ₯Ό μ μΈν  λ μ€μ²΄ν λΆκ° νμ
μΌλ‘ varargs λ§€κ°λ³μλ₯Ό μ μΈνλ©΄ μ»΄νμΌλ¬κ° κ²½κ³ λ₯Ό 보λΈλ€.
warning: [unchecked] Possible heap pollution from
  parameterized vararg type List<String>
λ§€κ°λ³μν νμ
 (parameterized type) μ λ³μκ° λ€λ₯Έ κ°μ²΄λ₯Ό μ°Έμ‘°νλ©΄ ν (heap) μ€μΌμ΄ λ°μνλ€λ μλ―Έλ‘
λ€λ₯Έ νμ
μ κ°μ²΄λ₯Ό μ°Έμ‘°νλ μν©μμ μ»΄νμΌλ¬κ° μλ μμ±ν νλ³νμ΄ μ€ν¨ν  μ μλ€.
μ λ€λ¦ κ°λ³μΈμ (varargs) λ°°μ΄ λ§€κ°λ³μμ κ°μ μ μ₯νλκ²μ μμ νμ§ μλ€.
μλ μμ λ₯Ό 보μ
static void dangerous(List<String>... stringLists) {
  List<Integer> intList = List.of(42);
  Object[] objects = stringLists;
  objects[0] = intLists;            // ν μ€μΌ λ°μ
  String s = stringLists[0].get(0)  // ClassCastException - ν λ³ν λ°μ
}
μλ°μμλ μ κ°μ μνμ±μ μΈμ§νκ³ λ λνμ μΌλ‘ μλμ κ°μ λ©μλλ₯Ό μ 곡νλ€.
Array.asList(T... a)Collections.addAll(Collection<? super T> c, T... elements)EnumSet.of(E first, E... rest)
μ λ€λ¦μ΄λ νΉμ λ§€κ°λ³μν νμ
μ κ°λ³μΈμ (varargs) νμ
μ λ§€κ°λ³μλ₯Ό λ°λ λͺ¨λ  λ©μλμμλ @SafeVarargs λ₯Ό λ¬μμ€μΌ νλ€.
μ΄λ κ°λ³μΈμ (varargs) νμ μ λ§€κ°λ³μ λ°°μ΄μ μ무κ²λ μ μ₯ν΄μ μλλ©°, κ·Έ λ°°μ΄ νΉμ 볡μ λ³Έμ μ λ’°ν μ μλ μ½λμ λ ΈμΆνλ μλκ²μ΄ μμΉμ΄λ€.
Item 33 νμ μμ  μ΄μ’ 컨ν μ΄λλ₯Ό κ³ λ €νλΌ
컨ν μ΄λ λμ ν€λ₯Ό λ§€κ°λ³μν μν€κ³ , 컨ν μ΄λμ κ°μ λ£κ±°λ λΊ λ λ§€κ°λ³μν ν ν€λ₯Ό ν¨κ» μ 곡νλ€.
public class Favorites {
  public <T> void putFavorite(Class<T> type, T instance);
  public <T> T getFavorite(Class<T> type);
}
public static void main(String[] args) {
  Favorites f = new Favorites();
  f.putFavorite(String.class, "Java");
  f.putFavorite(Integer.class, 0xcafebabe);
  f.putFavorite(Class.class, Favorites.class);
  String favoriteString = f.getFavorite(String.class);
  int favoriteInteger = f.getFavorite(Integer.class);
  Class<?> favoriteClass = f.getFavorite(Class.class);
  System.out.println("%s %x%n", favoriteString, favoriteInteger, favoriteClass.getName());
}
Java cafebabe Favorites
Favorites μΈμ€ν΄μ€λ String μ μμ²νλλ° Integer λ₯Ό λ°ννλ μΌμ μ λ μλ€.
μ΄λ λͺ¨λ  ν€μ νμ
μ΄ κ°κ° λΆλ¦¬λμ΄ μμ΄ μΌλ°μ μΈ λ°±κ³Ό λ¬λ¦¬ μ¬λ¬κ°μ§ νμ
μ μμλ₯Ό λ΄μ μ μλ€.
λ°λΌμ Favorites μ νμ
 μμ  μ΄μ’
컨ν
μ΄λ λΌκ³  νλ€.
μλλ Favorites μ ꡬνμ΄λ€.
public class Favorites {
    private Map<Class<?>, Object> favorites = new HashMap<>();
    public <T> void putFavorite(Class<T> type, T instance) {
      favorites.put(Objects.requireNonNull(type), instance);
    }
    public <T> T getFavorite(Class<T> type) {
      return type.cast(favorites.get(type));
    }
}
μ°Έκ³ μλ£