β μλ° μ λ€λ¦μ 곡λ³μ± & μμΌλμΉ΄λ μλ²½ μ΄ν΄
μλ°μ 곡λ³μ± / λ°κ³΅λ³μ±
μ λ€λ¦μ μμΌλμΉ΄λλ₯Ό λ°°μ°κΈ° μμ μ μ μ§μμΌλ‘ μκ³ λμ΄κ°μΌν κ°λ μ΄ μλ€.
μ‘°κΈ λμ΄λ μλ νλ‘κ·Έλλ° λΆλΆμ νμ΅ νλ€λ³΄λ©΄ νλ²μ―€μ λ€μ΄λ³Όμ μλ 곡λ³μ±(Covariance) / λ°κ³΅λ³μ±(Contravariance) ν©μ³μ 'λ³μ±(Variance)' μ΄λΌνλ κ°λ μ΄λ€.
λ³μ±μ νμ μ μμ κ³μΈ΅ κ΄κ³μμ μλ‘ λ€λ₯Έ νμ κ°μ μ΄λ€ κ΄κ³κ° μλμ§λ₯Ό λννλ μ§νμ΄λ€. κ·Έλ¦¬κ³ κ³΅λ³μ±μ μλ‘ λ€λ₯Έ νμ κ°μ ν¨κ» λ³ν μ μλ€λ νΉμ§μ λ§νλ€. μ΄λ₯Ό κ°μ²΄ μ§ν₯ κ°λ μΌλ‘ νννμλ©΄ Liskov μΉν μμΉμ ν΄λΉλλ€.
μλ₯Όλ€μ΄ λ°°μ΄(Array)κ³Ό 리μ€νΈ(List)κ° μλ€κ³ νμ. μλ°μμ κ° λ³μ±μ νΉμ§μ λ€μκ³Ό κ°μ΄ λλ€.
- κ³΅λ³ : S κ° T μ νμ νμ
μ΄λ©΄,
- S[] λ T[] μ νμ νμ μ΄λ€.
- List<S> λ List<T> μ νμ νμ μ΄λ€.
- λ°κ³΅λ³ : S κ° Tμ νμ νμ
μ΄λ©΄,
- T[] λ S[] μ νμ νμ μ΄λ€. (곡λ³μ λ°λ)
- List<T> λ List<S> μ νμ νμ μ΄λ€. (곡λ³μ λ°λ)
- λ¬΄κ³΅λ³ / λΆκ³΅λ³ : S μ T λ μλ‘ κ΄κ³κ° μλ€.
- List<S> μ List<T> λ μλ‘ λ€λ₯Έ νμ μ΄λ€.
μΈλ» 보면 λ€νμ±μ μ μΊμ€ν , λ€μ΄μΊμ€ν μ λ§νλ κ²κ³Ό λΉμ·ν΄λ³΄μΈλ€. μ§κΈ λ μλΆλ€μ΄ λλΌκ³ μλ κ²μ΄ λ§λ€.
μ΄λ₯Ό μλ° μ½λλ‘ λνλ΄λ³΄μλ©΄ λ€μκ³Ό κ°λ€.
// 곡λ³μ±
Object[] Covariance = new Integer[10];
// λ°κ³΅λ³μ±
Integer[] Contravariance = (Integer[]) Covariance;
// 곡λ³μ±
ArrayList<Object> Covariance = new ArrayList<Integer>();
// λ°κ³΅λ³μ±
ArrayList<Integer> Contravariance = new ArrayList<Object>();
κ·Έλ¬λ λ°°μ΄κ³Ό λ¬λ¦¬ μ λ€λ¦ μμ μ½λλ μλ°μμ λμκ°μ§ μλλ€. μλνλ©΄ μλ°λ μΌλ°μ μΌλ‘ μ λ€λ¦ νμ μ λν΄μ 곡λ³μ± / λ°κ³΅λ³μ±μ μ§μνμ§ μκΈ° λλ¬Έμ΄λ€. μ¦, μλ°μ μ λ€λ¦μ 무곡λ³μ μ±μ§μ μ§λλ€λΌκ³ μ μ λ΄λ¦΄ μ μλ€.
μ λ€λ¦μ 곡λ³μ±μ΄ μλ€
κ°μ²΄ νμ μ μν κ΄κ³κ° μλ€
μ΄λΆλΆμ μ°λ¦¬κ° λ무λλ μ μκ³ μλ λ€νμ±(polymorphism)μ μ±μ§μ μμ΄λ€.
Object νμ μΌλ‘ μ μΈν parent λ³μμ Integer νμ μΌλ‘ μ μΈν child λ³μκ° μλλ° κ°μ²΄ μ§ν₯ νλ‘κ·Έλλ°μμ μ΄λ€ λΌλ¦¬ μλ‘ κ°μ μΊμ€ν μ΄ κ°λ₯νλ€.
Object parent = new Object();
Integer child = new Integer(1);
parent = child; // λ€νμ± (μ
μΊμ€ν
)
Object parent = new Integer(1);
Integer child;
child = (Integer) parent; // λ€νμ± (λ€μ΄μΊμ€ν
)
μΌλ° ν΄λμ€κ° μλ μ λ€λ¦ ν΄λμ€μ¬λ λκ°μ΄ λ€νμ±μ΄ μ μ©λλ 건 λ§μ°¬κ°μ§ μ΄λ€.
λνμ μΌλ‘ 컬λ μ νλ μμν¬μ Collection κ³Ό κ·Έμ νμμΈ ArrayList λ μλ‘ μ‘°μ-μμ μμ κ΄κ³μ μκΈ° λλ¬Έμ μΊμ€ν μ΄ κ°λ₯νλ€.
Collection<Integer> parent = new ArrayList<>();
ArrayList<Integer> child = new ArrayList<>();
parent = child; // λ€νμ± (μ
μΊμ€ν
)
μ λ€λ¦ νμ μ μνκ΄κ³κ° μλ€
λ°λ©΄μ μ λ€λ¦μ νμ νλΌλ―Έν°(κΊΎμ κ΄νΈ) λΌλ¦¬λ νμ μ΄ μ무리 μμ κ΄κ³μ λμΈλ€ νλ€ μΊμ€ν μ΄ λΆκ°λ₯νλ€. μλνλ©΄ μ λ€λ¦μ λ¬΄κ³΅λ³ μ΄κΈ° λλ¬Έμ΄λ€. μ λ€λ¦μ μ λ¬λ°μ λ± κ·Έ νμ μΌλ‘λ§ μλ‘ μΊμ€ν μ΄ κ°λ₯νλ€.
ArrayList<Object> parent = new ArrayList<>();
ArrayList<Integer> child = new ArrayList<>();
parent = child; // ! μ
μΊμ€ν
λΆκ°λ₯
child = parent; // ! λ€μ΄μΊμ€ν
λΆκ°λ₯
μ¦, κΊΎμ κ΄νΈ λΆλΆμ μ μΈν μμ νμ (Raw Type) λΆλΆμ 곡λ³μ±μ΄ μ μ©λμ§λ§, κΊΎμ κ΄νΈ μμ μ€μ νμ 맀κ°λ³μμ λν΄μλ μ μ©μ΄ λμ§ μλλ€κ³ μ 리ν μ μλ κ²μ΄λ€.
곡λ³μ±μ΄ μμΌλ©΄ λνλλ λ¬Έμ μ
μ΄ νΉμ§μ΄ μ λ¬Έμ μκ° λλλ©΄μ 맀κ°λ³μλ‘ μ λ€λ¦μ μ¬μ©ν λ, μΈλΆμμ λμ λλ μΈμμ μΊμ€ν λ¬Έμ λ‘ μΈν΄ μ λ‘μ¬νμ΄ λ°μνκΈ° λλ¬Έμ΄λ€.
μλ₯Ό λ€μλ©΄ 리μ€νΈλ₯Ό μΈμλ‘ λ°μ μνν΄μ μΆλ ₯ν΄μ£Όλ print λ©μλκ° μλ€κ³ νμ. λ°°μ΄μ μ΄μ©ν μλ μ½λλ λ¬Έμ κ° μλ€.
public static void print(Object[] arr) {
for (Object e : arr) {
System.out.println(e);
}
}
public static void main(String[] args) {
Integer[] integers = {1, 2, 3};
print(integers); // [1, 2, 3]
}
μ΄λ²μ λ°°μ΄μ΄ μλ 리μ€νΈμ μ λ€λ¦ κ°μ²΄λ‘ λ겨보μ. κ·Έλ¬λ©΄ λ©μλ νΈμΆ λΆλΆμμ μ»΄νμΌ μλ¬κ° λ°μνλ€.
public static void print(List<Object> arr) {
for (Object e : arr) {
System.out.println(e);
}
}
public static void main(String[] args) {
List<Integer> integers = Arrays.asList(1, 2, 3);
print(integers); // ! Error
}
λ°°μ΄ κ°μ κ²½μ° print λ©μλμ 맀κ°λ³μλ‘ μκ·λ¨ΌνΈκ° λμ΄κ°λ Integer[] λ°°μ΄ νμ
μ΄ Object[] λ°°μ΄ νμ
μΌλ‘ μμ°μ€λ½κ² μ
μΊμ€ν
μ΄ μ μ©λμ΄ λ¬Έμ κ° μμ§λ§, 리μ€νΈ μ λ€λ¦ κ°μ κ²½μ° νμ
νλΌλ―Έν°κ° μ€λ‘μ§ λκ°μ νμ
λ§ λ°κΈ° λλ¬Έμ μΊμ€ν
μ΄ λμ§ μμ κ·Έλ° κ²μ΄λ€.
κ·Έλ λ€λ©΄ μΈλΆλ‘λΆν° κ°μ λ°λ 맀κ°λ³μμ μ λ€λ¦ νμ νλΌλ―Έν°λ₯Ό Integerλ‘ κ³ μ λ νμ μΌλ‘ μμ±ν΄μ£Όμ΄μΌ νλλ°, νλ‘κ·Έλ¨μ μ€νλΆμμ λ°λμ Integer νμ λ§ λ€μ΄μ¨λ€λ 보μ₯λ μμΌλ©°, λ§μΌ Double νμ΄λ μλλ©΄ μμ νμ μΈ Number νκ³Ό κ°μ λ€λ₯Έ νμ μ κ°λ λ°κ³ μΆμ κ²½μ°, λ©μλλ₯Ό μ€λ²λ‘λ©νμ¬ μ¦λΉνκ² μ½λ©ν΄μΌ νλ€.
public static void print(List<Integer> arr) {
}
public static void print(List<Double> arr) {
}
public static void print(List<Number> arr) {
}
...
κ·ΈλΌ μ λ€λ¦μ μλ°μ νΉμ§μ΄λΌκ³ ν μ μλ κ°μ²΄ μ§ν₯μ μ ν μ΄μ©νμ§ λͺ»νλ κ²μ΄ λλλ°, κ²°κ΅ μμ κ°μ΄ λΉν¨μ¨μ μΌλ‘ μ½λ©ν΄μΌ νλκ²μΌκΉ? λ°λ‘ μ΄λ₯Ό ν΄κ²°νκΈ° μν΄ λμ¨ κΈ°λ₯μ΄ μ λ€λ¦ μμΌλμΉ΄λ μΈ κ²μ΄λ€.
μ λ€λ¦ μμΌλμΉ΄λ
μλ° μ λ€λ¦μ μ΄μ©ν΄ νλ‘κ·Έλλ° ν λ κ°νΉ ν΄λμ€ μ μλ¬Έμ 보λ€λ³΄λ©΄ κΊΎμ κ΄νΈ ? λ¬Όμν κΈ°νΈκ° μλ κ²μ νλ²μ―€ λ³Έ μ μ΄ μμ κ²μ΄λ€. μ΄ λ¬Όμνκ° μμΌλμΉ΄λμ΄λ©°, λ¬Όμνμ μλ―Έ λ΅κ² μ΄λ€ νμ
μ΄λ λ μ μλ€λ λ»μ μ§λκ³ μλ€.
νμ§λ§ λ¨μν <?> λ‘ μ¬μ©νλ©΄ Object νμ
κ³Ό λ€λ¦μ΄ μμ΄μ§λ―λ‘ λ³΄ν΅ μ λ€λ¦ νμ
νμ μ°μ°μμ ν¨κ» μ°μΈλ€.
μμΌλ μΉ΄λμ νμ
λ²μλ₯Ό μ ννλ ν€μλλ extends μ λλΆμ΄ superκ° μλ€. μ΄ extends μ super ν€μλλ ν΄λμ€ μμ κ΄κ³μμμ νμ
μ νμ νμ
μΌλ‘λ§ μ νν μ§, μμ νμ
μΌλ‘λ§ μ νν μ§μ λ°λΌ μ°μμκ° λ€λ₯΄κ² λλ€.
μμΌλμΉ΄λ | λ€μ΄λ° | μ€λͺ |
<?> | Unbounded wildcards λΉνμ μ μμΌλ μΉ΄λ |
μ ν μμ (λͺ¨λ νμ μ΄ κ°λ₯) |
<? extends U> | Upper Bounded Wildcards μν κ²½κ³ μμΌλμΉ΄λ |
μμ ν΄λμ€ μ ν (Uμ κ·Έ μμλ€λ§ κ°λ₯) μνμ΄ UλΌ μν κ²½κ³λΌκ³ νλ€. |
<? super U> | Lower Bounded Wildcards νν κ²½κ³ μμΌλμΉ΄λ |
νμ ν΄λμ€ μ ν (Uμ κ·Έ μ‘°μλ€λ§ κ°λ₯) ννμ΄ UλΌ νν κ²½κ³λΌκ³ νλ€. |
μμΌλμΉ΄λμ 곡λ³μ± / λ°κ³΅λ³μ±
λ€μμ μ€μ ArrayListμ κΈ°λ₯μ€ μΌλΆ λ©μλλ§ μΆλ €μ λ³λλ‘ μ¬κ΅¬μ±ν MyArrayList μ λ€λ¦ ν΄λμ€ μμ μ΄λ€.
MyArrayList μμ±μ(Constructor)λ₯Ό 보면, 컬λ μ (Collection)μ λ°μ 컬λ μ μ μννμ¬ μ»¬λ μ λ΄μ λ€μ΄μλ λͺ¨λ μμλ₯Ό λ΄λΆ λ°°μ΄(Object[])μ λ£μ΄ μ λ€λ¦ κ°μ²΄λ₯Ό μμ°νλ μν μ νλ€.
MyArrayListμ clone λ©μλλ₯Ό 보면, λΉ μ»¬λ μ (Collection)μ λ°μ λ΄λΆ λ°°μ΄μ μννμ¬ λ°°μ΄ λ΄μ λ€μ΄μλ λͺ¨λ μμλ₯Ό 컬λ μ μ λ£μ΄μ£Όλ, 맀κ°λ³μλ‘ λ°μ μ λ€λ¦ κ°μ²΄λ₯Ό μλΉνλ μν μ νλ€.
class MyArrayList<T> {
Object[] element = new Object[5];
int index = 0;
// μΈλΆλ‘λΆν° 리μ€νΈλ₯Ό λ°μμ 맀κ°λ³μμ λͺ¨λ μμλ₯Ό λ΄λΆ λ°°μ΄μ μΆκ°νμ¬ μΈμ€ν΄μ€ν νλ μμ±μ
public MyArrayList(Collection<T> in) {
for (T elem : in) {
element[index++] = elem;
}
}
// μΈλΆλ‘λΆν° 리μ€νΈλ₯Ό λ°μμ λ΄λΆ λ°°μ΄μ μμλ₯Ό λͺ¨λ 맀κ°λ³μμ μΆκ°ν΄μ£Όλ λ©μλ
public void clone(Collection<T> out) {
for (Object elem : element) {
out.add((T) elem);
}
}
@Override
public String toString() {
return Arrays.toString(element); // λ°°μ΄ μμλ€ μΆλ ₯
}
}
λμΉλ₯Ό μ±λ―μ΄ μ΄ μ½λλ μ μ°νμ§ μλ€.
MyArrayListμ μ μλ λ°κ³ μ€μλ λ°κ² νκΈ°μν΄ μ λ€λ¦ νμ 맀κ°λ³μλ‘ Numberλ‘ μ§μ ν΄ μ£Όμλ€. κ·Έλ¦¬κ³ Integer 맀κ°λ³μν νμ μ Collection κ°μ²΄λ₯Ό MyArrayList μμ±μλ‘ λ£μ΄μ£Όμλ€.
public static void main(String[] args) {
// MyArrayListμ μ λ€λ¦ T νμ
μ Number
MyArrayList<Number> list;
// MyArrayList μμ±νκΈ°
Collection<Integer> col = Arrays.asList(1, 2, 3, 4, 5);
list = new MyArrayList<>(col); // ! ERROR
// MyArrayList μΆλ ₯
System.out.println(list);
}
νμ§λ§ κ²°κ³Όλ μλ»κ±΄ μ»΄νμΌ μλ¬μ΄λ€. μλνλ©΄ 맀κ°λ³μλ Collection<Number> νμ
μΌλ‘ λ°λλ° Collection<Integer> κ°μ²΄λ₯Ό μ λ¬ν΄μ£ΌμκΈ° λλ¬Έμ΄λ€. Integerλ Numberλ₯Ό μμνμ¬ λμ λΆλͺ¨-μμ κ΄κ³μ΄μ§λ§ μ λ€λ¦μ νμ
νλΌλ―Έν°λ κΈ°λ³Έμ μΌλ‘ 곡λ³μ±μ΄ μμ΄ μ±λ¦½λμ§ μκ² λλ κ²μ΄λ€.
κ·Έλμ νλ μ μμ΄ col κ°μ²΄μ μ λ€λ¦ νμ
μ λκ°μ΄ Collection<Number>λ‘ λ§μΆ°μ£Όκ³ λμμΌ MyArrayList μΈμ€ν΄μ€λ₯Ό μμ°ν μ μκ² λμλ€.
μ΄λ²μλ MyArrayListμ clone λ©μλμ λΉ LinkedListλ₯Ό μΈμλ‘ μ€μ MyArrayListμ λ€μ΄μλ μμλ€μ 볡μ¬νμ¬ λ£κΈ°μν΄ λ©μλλ₯Ό νΈμΆνμλ€. μ΄λ String νμ μ΄λ Number νμ μ΄λ λͺ¨λ νμ μ λ°μ΄ν°λ₯Ό λ°μ μ μκ² νκΈ° μν΄ Object νμ νλΌλ―Έν°λ‘ μ€μ νμλ€.
public static void main(String[] args) {
// MyArrayListμ μ λ€λ¦ T νμ
μ Number
MyArrayList<Number> list;
// MyArrayList μμ±νκΈ°
Collection<Number> col = Arrays.asList(1, 2, 3, 4, 5);
list = new MyArrayList<>(col);
// LinkedList μ MyArrayList μμλ€ λ³΅μ¬νκΈ°
List<Object> temp = new LinkedList<>();
temp = list.clone(temp); // ! ERROR
// LinkedList μΆλ ₯
System.out.println(temp);
}
μμλ κ²°κ³Όλ κ½μ΄λ€. μ λ€λ¦μ λ°κ³΅λ³ μμ μ±λ¦½λμ§ μκΈ° λλ¬Έμ Collection<Number>μ Collection<Object>κ° λ€μ΄κ°λ νμλ μ±λ¦½λμ§ μλλ€.
μ΄μ²λΌ μλ°μ μ λ€λ¦μ κΈ°λ³Έμ μΌλ‘ 곡λ³, λ°κ³΅λ³μ μ§μνμ§ μμ§λ§, <? extends T> , <? super T> μμΌλμΉ΄λλ₯Ό μ΄μ©νλ©΄ μ»΄νμΌλ¬ νΈλ¦μ ν΅ν΄ 곡λ³, λ°κ³΅λ³μ΄ μ μ©λλλ‘ μ€μ ν μ μλ€. λμ μ 리νμλ©΄ λ€μκ³Ό κ°λ€.
- μν κ²½κ³ μμΌλμΉ΄λ
<? extends T>: 곡λ³μ± μ μ© - νν κ²½κ³ μμΌλμΉ΄λ
<? super T>: λ°κ³΅λ³μ± μ μ©
μν κ²½κ³ μμΌλμΉ΄λ (곡λ³)
MyArrayListλ₯Ό μ€κ³ν κ°λ°μμ μλλ Collection<Integer> μ Collection<Double> κ°μ²΄λ₯Ό μμ±μμ μΈμλ‘ λͺ¨λ λ°μ λ°°μ΄μ λ£κ³ μΆμ κ²μ΄λ€. μ΄λ₯Ό μν΄ μ λ€λ¦μ μν κ²½κ³ μμΌλμΉ΄λ(Upper Bounded Wildcards)λ₯Ό μ μ©μν¨λ€.
class MyArrayList<T> {
Object[] element = new Object[5];
int index = 0;
// μΈλΆλ‘λΆν° 리μ€νΈλ₯Ό λ°μμ 맀κ°λ³μμ λͺ¨λ μμλ₯Ό λ΄λΆ λ°°μ΄μ μΆκ°νμ¬ μΈμ€ν΄μ€ν νλ μμ±μ
public MyArrayList(Collection<? extends T> in) {
for(T elem : in) {
element[index++] = elem;
}
}
// ...
}
public static void main(String[] args) {
// MyArrayListμ μ λ€λ¦ T νμ
μ Number
MyArrayList<Number> list;
// MyArrayList μμ±νκΈ°
Collection<Integer> col = Arrays.asList(1, 2, 3, 4, 5);
list = new MyArrayList<>(col);
// MyArrayList μΆλ ₯
System.out.println(list); // [1, 2, 3, 4, 5]
}
κ·Έλ¬λ©΄ κ³΅λ³ μ±μ§μ΄ μ μ©λμ΄ μ»΄νμΌ μλ¬ μμ΄ μ μμ μΌλ‘ MyArrayListμ μμκ° λ€μ΄κ° μμ°λμμμ νμΈ ν μ μλ€.
μ΄λ₯Ό ν΄λμ€ μμκ΄κ³λ‘ νννμλ©΄ λ€μκ³Ό κ°μ΄ 그릴μ μλ€.
μ¦, Integer κ° Objectμ νμ νμ μΌ κ²½μ°, C<Integer>λ C<? extends Object>μ νμ νμ μ΄ λλ κ²μ΄λ€.
ArrayList<? extends Object> parent = new ArrayList<>();
ArrayList<? extends Integer> child = new ArrayList<>();
parent = child; // 곡λ³μ± (μ λ€λ¦ νμ
μ
μΊμ€ν
)
νν κ²½κ³ μμΌλμΉ΄λ (λ°κ³΅λ³)
MyArrayListμ clone λ©μλλ₯Ό μ€κ³ν κ°λ°μμ μλλ MyArrayListμ μ λ€λ¦ νμ νλΌλ―Έν°κ° 무μμ΄λ μΈμλ‘ λ°μ 컬λ μ 맀κ°λ³μμ μμλ€μ λͺ¨λ μ§μ΄λ£κ³ μΆμ κ²μ΄λ€. μ΄λ₯Ό μν΄ μ λ€λ¦μ νν κ²½κ³ μμΌλμΉ΄λ(Lower Bounded Wildcards)λ₯Ό μ μ©μν¨λ€.
class MyArrayList<T> {
Object[] element = new Object[5];
int index = 0;
// μΈλΆλ‘λΆν° 리μ€νΈλ₯Ό λ°μμ 맀κ°λ³μμ λͺ¨λ μμλ₯Ό λ΄λΆ λ°°μ΄μ μΆκ°νμ¬ μΈμ€ν΄μ€ν νλ μμ±μ
public MyArrayList(Collection<? extends T> in) {
for (T elem : in) {
element[index++] = elem;
}
}
// μΈλΆλ‘λΆν° 리μ€νΈλ₯Ό λ°μμ λ΄λΆ λ°°μ΄μ μμλ₯Ό λͺ¨λ 맀κ°λ³μμ μΆκ°ν΄μ£Όλ λ©μλ
public void clone(Collection<? super T> out) {
for (Object elem : element) {
out.add((T) elem);
}
}
@Override
public String toString() {
return Arrays.toString(element); // λ°°μ΄ μμλ€ μΆλ ₯
}
}
public static void main(String[] args) {
// MyArrayListμ μ λ€λ¦ T νμ
μ Number
MyArrayList<Number> list = new MyArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
// LinkedList μ MyArrayList μμλ€ λ³΅μ¬νκΈ°
List<Object> temp = new LinkedList<>();
temp = list.clone(temp);
// LinkedList μΆλ ₯
System.out.println(temp); // [1, 2, 3, 4, 5]
}
κ·Έλ¬λ©΄ λ°κ³΅λ³ μ±μ§μ΄ μ μ©λμ΄ μ»΄νμΌ μλ¬ μμ΄ μ μμ μΌλ‘ MyArrayListμ μμκ° λ€μ΄κ° μλΉλμμμ νμΈ ν μ μλ€.
μ΄λ₯Ό ν΄λμ€ μμκ΄κ³λ‘ νννμλ©΄ λ€μκ³Ό κ°μ΄ 그릴μ μλ€.
μ¦, Objectκ° Integerμ μμ νμ μΌ κ²½μ°, C<Object>λ C<? super Integer>μ νμ νμ μ΄ λλ κ²μ΄λ€.
ArrayList<? super Object> parent = new ArrayList<>();
ArrayList<? super Integer> child = new ArrayList<>();
child = parent; // λ°κ³΅λ³μ± (μ λ€λ¦ λ€μ΄μΊμ€ν
)
μ΄λλ€ μ¨μΌν μ§λ μ 맀ν μ΄λ° κ±°κΎΈλ‘μ μμ κ΄κ³λ μμ μ¬λ‘μ κ°μ΄ μΈμ€ν΄μ€ν λ ν΄λμ€μ μ λ€λ¦λ³΄λ€ μμ νμ μ λ°μ΄ν°λ₯Ό μ μ¬ν΄μΌ ν λ λ°κ³΅λ³μ μ¬μ©νλ€κ³ μ΄ν΄νλ©΄ λλ€. μ΄λ¬ν μ λ€λ¦μ λ³μ±μ μ μ νκ² μ¬μ©νλ©΄ μ μ°ν μ½λλ₯Ό μμ±ν μ μκ² λλ€.
μλ°μ μ λ€λ¦μ κΈ°λ³Έμ μΌλ‘ λ³μ±μ΄ μμ§λ§, νμ μ μμΌλμΉ΄λ νμ μ ν΅ν΄ νμ μ 곡λ³μ± λλ λ°κ³΅λ³μ±μ μ§μ ν μ μλ€. μ΄λ κ² νμ 맀κ°λ³μ μ§μ μ λ³μ±μ μ νλ μλ°μ λ°©μμ μ¬μ©μ§μ λ³μ±(use-site variance)μ΄λΌ νλ€.
μλ°μ κ°μ΄ JVMμ μ΄μ©νλ μ½νλ¦°μμλ μ¬μ©μ μ§μ λ³μ±μ μ 곡νλ€.
λΉνμ μ μμΌλ μΉ΄λ
μ λ€λ¦μ extends, super λ²μ λ°μ§μ§ μκ³ μ¬ννκ² <?> λΉνμ μ μμΌλ μΉ΄λλ‘λ§ κ΅¬μ±ν΄μ£Όλ©΄ μ΄λ»κ² λ κΉ?
μ΄λ ν νμ λ μ¬ μ μλ€λ μ μ μΉνΈν€μ΄μ§λ§, λμμ μ΄λ ν νμ λ μ¬ μ μλ λ¬Έμ λλ¬Έμ 맀κ°λ³μλ₯Ό κΊΌλ΄κ±°λ μ μ₯νλ λ‘μ§μ λ Όλ¦¬μ μλ¬κ° λ°μνκ² λλ€.
public MyArrayList(Collection<?> in) {
for (T elem : in) {
element[index++] = elem;
}
}
public void clone(Collection<?> out) {
for (Object elem : element) {
out.add((T) elem);
}
}
νμ§λ§ extends, super λ₯Ό ν΅ν΄ μμΌλμΉ΄λμ κ²½κ³λ₯Ό μ ν΄μ£Όλ©΄, νμ μ λ²μ λ΄μμ μΆλ‘ μ νκΈ° λλ¬Έμ κ²½κ³ λ λ°μν μ§λΌλ μ€λ₯λ λμ§μκ² λλ κ²μ΄λ€.
μμΌλμΉ΄λ κΊΌλ΄κΈ° / λ£κΈ° μ μ½
μμΌλμΉ΄λ κ²½κ³ λ²μ
λ€μκ³Ό κ°μ΄ ν΄λμ€ νμ μ μμ κ΄κ³κ° μλ€κ³ κ°μ νμ. μ΄λ₯Ό μμλ‘ νμ μ ν λ²μμ λν΄ μμ λ³΄κ² λ€.
// μ λ€λ¦ νμ
ν΄λμ€
class Box<T> {
...
}
// νμ
κ³μΈ΅ κ΄κ³
class Food {
}
class Fruit extends Food {
}
class Vegetable extends Food {
}
class Apple extends Fruit {
}
class Banana extends Fruit {
}
class Carrot extends Vegetable {
}
μν κ²½κ³ <? extends U>
- νμ 맀κ°λ³μμ λ²μλ U ν΄λμ€μ΄κ±°λ, Uλ₯Ό μμν νμ ν΄λμ€ (Uμ Uμ μμ νμ λ§ κ°λ₯)
- μνμ λ» : νμ μ μ΅κ³ νλλ U λΌλ μλ―Έ. (μ΅λ U μ΄ν)
Box<? extends Fruit> box1 = new Box<Fruit>();
Box<? extends Fruit> box2 = new Box<Apple>();
Box<? extends Fruit> box3 = new Box<Banana>();
νν κ²½κ³ <? super U>
- νμ 맀κ°λ³μμ λ²μλ U ν΄λμ€μ΄κ±°λ, Uκ° μμν μμ ν΄λμ€ (Uμ Uμ μ‘°μ νμ λ§ κ°λ₯)
- ννμ λ» : νμ μ μ΅μ νλλ U λΌλ μλ―Έ. (μ΅μ U μ΄μ)
Box<? super Fruit> box1 = new Box<Fruit>();
Box<? super Fruit> box2 = new Box<Food>();
Box<? super Fruit> box3 = new Box<Object>();
λΉκ²½κ³ <?>
- νμ 맀κ°λ³μμ λ²μλ μ νμ΄ μλ€. (λͺ¨λ κ°λ₯)
< ? extends Object >μ μ€μ νν
Box<?> box1 = new Box<Vegetable>();
Box<?> box2 = new Box<Fruit>();
Box<?> box3 = new Box<Food>();
Box<?> box3 = new Box<Carrot>();
μμΌλμΉ΄λ κ²½κ³ κΊΌλ΄κΈ° / λ£κΈ° κ³ μ°°
μ΄ ννΈλ λμ΄λκ° κ°μκΈ° μμ§ μμΉνλ λΆλΆμ΄λ€.
μμΌλμΉ΄λλ₯Ό νν κ²½κ³λ‘ μ§μ νλκ° μν κ²½κ³λ‘ μ§μ νλκ° μ λ°λΌ μ λ€λ¦ νμ κ°μ²΄μ μμλ₯Ό κΊΌλ΄κ±°λ μ§μ΄λ£κΈ° νμμ λν΄ λ³΅μ‘ν μ μ½μ΄ 걸리기 λλ¬Έμ΄λ€. μ€λ¬΄μ μνλ νμ§μλ€λ μμ£Ό νκΉλ¦¬λ λΆλΆμ΄λ©°, μ μ μ½μ΄ 걸리λμ§ λ Όλ¦¬μ μΌλ‘ νμ μ μΆλ‘ νμ¬ μ¬λμλ κ³ λ―Όμ΄ νμνλ€. (머리 νκ°λ νμ!)
μ λ€λ¦ νμ ν΄λμ€λ‘λ κ°μ₯ μ΅μν List μλ£νμ μ΄μ©ν΄ μλ₯Ό λ€κ² λ€.
λ μλΆλ€μκ² TIPμ λ리μλ©΄ 'λ κ² κ°μλ° μ μλμ§?' λΌκ³ μλ¬Έμ νν μΌμ΄μ€λ λλΆλΆ ν΄λμ€κ°
νμ κ΄κ³μ μμλ μλ‘ μΊμ€ν νμ¬ λνλλ λ¬Έμ μ λλ¬Έμ λ§νμλ€κ³ 보면 λλ€.
List<? extends U>
- GET : μμ νκ² κΊΌλ΄λ €λ©΄ U νμ μΌλ‘ λ°μμΌν¨
- SET : μ΄λ ν νμ μ μλ£λ λ£μμ μμ (nullλ§ μ½μ κ°λ₯)
- κΊΌλΈ νμ μ U / μ μ₯μ NO
λ©μλμ 맀κ°λ³μμ μ λ€λ¦ νμ
μ΄ <? extends Fruit> λΌλ κ²μ Apple, Banana, Fruit νμ
μ μ λ¬λ°μ λ΄λΆμμ λ€λ£°μ μλ€λ λ§μ΄λ€.
class FruitBox {
public static void method(List<? extends Fruit> item) {
// μμ νκ² κΊΌλ΄λ €λ©΄ Fruit νμ
μΌλ‘λ§ λ°μμΌνλ€
Fruit f1 = item.get(0);
Apple f2 = (Apple) item.get(0); // ! μ μ¬μ ERROR
Banana f3 = (Banana) item.get(0); // ! μ μ¬μ ERROR
}
}
public class Main {
public static void main(String[] args) {
List<Banana> bananas = new ArrayList<>(
Arrays.asList(new Banana(), new Banana(), new Banana())
);
FruitBox.method(bananas);
}
}
κ·Έλ°λ° κΊΌλ΄λ κ²(GET)μ΄ μ Fruit νμ μΌλ‘ λ°μμΌ λλλ©΄,
- λ§μΌ 맀κ°λ³μμ
List<Banana>νμ μΌλ‘ λ€μ΄μ¬ κ²½μ°Apple f2μ νμ μΊμ€ν μ΄ λΆκ°λ₯νκΈ° λλ¬Έμ΄λ€. - λ§μΌ 맀κ°λ³μμ
List<Fruit>νμ μΌλ‘ λ€μ΄μ¬ κ²½μ°Apple f2μ λ€μ΄ μΊμ€ν μ΄ λΆκ°λ₯νκΈ° λλ¬Έμ΄λ€. - μ΄λ¬ν λ Όλ¦¬ μ€λ₯λ‘ μμΌλμΉ΄λ μ΅μμ λ²μμΈ Fruit νμ μΌλ‘λ§ μμ νκ² κΊΌλΌμ μλ κ²μ΄λ€.
class FruitBox {
public static void method(List<? extends Fruit> item) {
// μ μ₯μ NO
item.add(new Fruit()); // ! ERROR
item.add(new Apple()); // ! ERROR
item.add(new Banana()); // ! ERROR
item.add(null); // null λ§ μ½μ
κ°λ₯
}
}
κ·Έλ¦¬κ³ μ μ₯ νλλ°(SET) μ΄λ ν νμ λ λΆκ°λ₯νλλ©΄,
- λ§μΌ 맀κ°λ³μμ
List<Banana>νμ μΌλ‘ λ€μ΄μ¬ κ²½μ° νμ κ°μ²΄μΈnew Apple()μ μ₯μ΄ λΆκ°λ₯νκΈ° λλ¬Έμ΄λ€. - λ§μΌ 맀κ°λ³μμ
List<Fruit>νμ μΌλ‘ λ€μ΄μ¬ κ²½μ°λ λ¬Έμ κ° μκ² μ§λ§ μμ λ Όλ¦¬ μ€λ₯ λλ¬Έμ κ·Έλ₯ μ»΄νμΌ μλ¬λ‘ μ²λ¦¬λλ€. - λ°λΌμ λ§μΌ 맀κ°λ³μμ κ°μ λ£κ³ μΆλ€λ©΄ 무쑰건 super μμΌλμΉ΄λλ₯Ό μ¬μ©νμ¬μΌ νλ€.
List<? super U>
- GET : μμ νκ² κΊΌλ΄λ €λ©΄ Object νμ μΌλ‘λ§ λ°μμΌνλ€
- SET : Uμ Uμ μμ νμ λ§ λ£μ μ μμ (Uμ μμνμ λΆκ°λ₯)
- κΊΌλΈ νμ μ Object / μ μ₯μ Uμ κ·Έμ μμλ§
λ©μλμ 맀κ°λ³μμ μ λ€λ¦ νμ
μ΄ <? super Fruit> λΌλ κ²μ Fruit, Food, Object νμ
μ μ λ¬λ°μ λ΄λΆμμ λ€λ£°μ μλ€λ λ§μ΄λ€.
class FruitBox {
public static void method(List<? super Fruit> item) {
// μμ νκ² κΊΌλ΄λ €λ©΄ Object νμ
μΌλ‘λ§ λ°μμΌνλ€
Object f1 = item.get(0);
Food f2 = (Food) item.get(0); // ! μ μ¬μ ERROR
Fruit f3 = (Fruit) item.get(0); // ! μ μ¬μ ERROR
Apple f4 = (Apple) item.get(0); // ! μ μ¬μ ERROR
Banana f5 = (Banana) item.get(0); // ! μ μ¬μ ERROR
}
}
public class Main {
public static void main(String[] args) {
List<Food> foods = new ArrayList<>(
Arrays.asList(new Food(), new Food(), new Food())
);
FruitBox.method(foods);
}
}
κ·Έλ°λ° κΊΌλ΄λ κ²μ΄ μ Object νμ μΌλ‘ λ°μμΌ λλλ©΄,
- λ§μΌ 맀κ°λ³μμ
List<Food>νμ μΌλ‘ λ€μ΄μ¬ κ²½μ°Fruit f3μ μΊμ€ν μ΄ λΆκ°λ₯νκΈ° λλ¬Έμ΄λ€. - μ΄λ¬ν λ Όλ¦¬ μ€λ₯λ‘ μμΌλμΉ΄λ μ΅μμ λ²μμΈ Object νμ μΌλ‘λ§ μμ νκ² κΊΌλΌμ μλ κ²μ΄λ€.
class FruitBox {
static void method(List<? super Fruit> item) {
// μ μ₯μ 무쑰건 Fruitμ κ·Έμ μμ νμ
λ§ λ£μμ μλ€
item.add(new Fruit());
item.add(new Apple());
item.add(new Banana());
item.add(new Object()); // ! ERROR
item.add(new Food()); // ! ERROR
}
}
κ·Έλ¦¬κ³ μ μ₯νλλ° κ±°κΎΈλ‘ Fruitκ³Ό κ·Έμ μμ νμ λ§ μ¬μ μλλ©΄,
- λ§μΌ 맀κ°λ³μμ
List<Fruit>νμ μΌλ‘ λ€μ΄μ¬ κ²½μ°new Food()λ₯Ό μ μ₯μ΄ λΆκ°λ₯νκΈ° λλ¬Έμ΄λ€. - λ°λΌμ μ΄λ ν νμ μ΄ μλ μ μΊμ€ν κ°λ₯ μνμΈ Fruit νμ μΌλ‘λ§ μ νλλ€.
List<?>
- GET : μμ νκ² κΊΌλ΄λ €λ©΄ Object νμ μΌλ‘λ§ λ°μμΌνλ€ (super μ νΉμ§)
- SET : μ΄λ ν νμ μ μλ£λ λ£μμ μμ (nullλ§ μ½μ κ°λ₯) (extends μ νΉμ§)
- κΊΌλΈ νμ μ Object / μ μ₯μ NO
λ©μλμ 맀κ°λ³μμ μ λ€λ¦ νμ
μ΄ <?> λΌλ κ²μ λͺ¨λ νμ
μ μ λ¬λ°μ λ΄λΆμμ λ€λ£°μ μλ€λ λ§μ΄λ€.
class FruitBox {
static void method(List<?> item) {
// κΊΌλ΄λ건 Object νμ
λ§ κ°λ₯
Object f1 = item.get(0);
Food f2 = (Food) item.get(0); // ! μ μ¬μ ERROR
Fruit f3 = (Fruit) item.get(0); // ! μ μ¬μ ERROR
Apple f4 = (Apple) item.get(0); // ! μ μ¬μ ERROR
Banana f5 = (Banana) item.get(0); // ! μ μ¬μ ERROR
}
}
class FruitBox {
static void method(List<?> item) {
// μ μ₯μ NO (nullλ§ μ μ₯)
item.add(new Object()); // ! ERROR
item.add(new Food()); // ! ERROR
item.add(new Fruit()); // ! ERROR
item.add(new Apple()); // ! ERROR
item.add(new Banana()); // ! ERROR
item.add(null);
}
}
μμΌλμΉ΄λ extends / super μ¬μ©μκΈ°
μΈμ μ΄λμ μ΄λλμ μμΌλμΉ΄λ <? extends T> λ₯Ό μ¬μ©ν΄μΌ ν μ§, <? super T> λ₯Ό μ¬μ©ν΄μΌ ν μ§ λ± λ¨Έλ¦Ώμμ μ‘νμ§ μλλ€. μ΄λ νμ
μμλ μμ£Ό κ³ λ―Όλλ μ¬νμ΄λ©°, κ·Έλμ μλ° κ°λ°μλΌλ©΄ νλ² μ―€ μ½μ΄λ΄μΌ νλ μ‘°μμ λΈλ‘ν(Joshua J. Bloch)μ μ μ Effective Javaμμλ μ΄μ λν΄μ PECS λΌλ 곡μμ μκ°νλ€.
PECS 곡μ
PECSλ, Producer-Extends / Consumer-Super λΌλ λ¨μ΄μ μ½μμΈλ° λ€μμ μλ―Ένλ€.
- μΈλΆμμ μ¨ λ°μ΄ν°λ₯Ό μμ°(Producer) νλ€λ©΄
<? extends T>λ₯Ό μ¬μ© (νμνμ μΌλ‘ μ ν) - μΈλΆμμ μ¨ λ°μ΄ν°λ₯Ό μλΉ(Consumer) νλ€λ©΄
<? super T>λ₯Ό μ¬μ© (μμνμ μΌλ‘ μ ν).
μ΄ ν¬μ€ν μ μ΄λ° ννΈμΈ μλ°μ 곡λ³μ± / λ°κ³΅λ³μ±μμ μ¬μ©ν μμ λ₯Ό λ€μ κ°μ Έμ μ΄ν΄λ³΄μ.
class MyArrayList<T> {
Object[] element = new Object[5];
int index = 0;
// μΈλΆλ‘λΆν° 리μ€νΈλ₯Ό λ°μμ 맀κ°λ³μμ λͺ¨λ μμλ₯Ό λ΄λΆ λ°°μ΄μ μΆκ°νμ¬ μΈμ€ν΄μ€ν νλ μμ±μ
public MyArrayList(Collection<? extends T> in) {
for (T elem : in) {
element[index++] = elem;
}
}
// μΈλΆλ‘λΆν° 리μ€νΈλ₯Ό λ°μμ λ΄λΆ λ°°μ΄μ μμλ₯Ό λͺ¨λ 맀κ°λ³μμ μΆκ°ν΄μ£Όλ λ©μλ
public void clone(Collection<? super T> out) {
for (Object elem : element) {
out.add((T) elem);
}
}
}
Producers Extend
μμ μμ μμ extends κ° μ°μ΄λ κ³³μ μμ±μ λ©μλμ 맀κ°λ³μ λΆλΆμ΄λ€. μ¦, μΈλΆμμ μ¨ λ°μ΄ν°λ₯Ό 맀κ°λ³μμ λ΄μ forλ¬ΈμΌλ‘ μννμ¬ MyArrayListλ₯Ό μΈμ€ν΄μ€ν(μμ±)νλ μμ°μ(Producer) μν μ νκ³ μλ€κ³ λ§ν μ μλ€.
class MyArrayList<T> {
Object[] element = new Object[5];
int index = 0;
// μΈλΆλ‘λΆν° 리μ€νΈλ₯Ό λ°μμ 맀κ°λ³μμ λͺ¨λ μμλ₯Ό λ΄λΆ λ°°μ΄μ μΆκ°νμ¬ μΈμ€ν΄μ€ν νλ μμ±μ
public MyArrayList(Collection<? extends T> in) {
for (T elem : in) {
element[index++] = elem;
}
}
...
}
Consumers Super
μΈλΆμμ 리μ€νΈλ₯Ό λ°μ μμλ₯Ό 볡μ¬νμ¬ μ μ¬νλ clone λ©μλμ 맀κ°λ³μμλ super μμΌλμΉ΄λ ν€μλκ° μ°μλ€. μ¦, MyArrayListμ λ΄λΆ λ°°μ΄μ μλΉνμ¬ λ§€κ°λ³μ 리μ€νΈμ μ μ¬νλ νμλ₯Ό νκ³ μλ€κ³ λ³Ό μ μλ κ²μ΄λ€.
class MyArrayList<T> {
Object[] element = new Object[5];
int index = 0;
...
// μΈλΆλ‘λΆν° 리μ€νΈλ₯Ό λ°μμ λ΄λΆ λ°°μ΄μ μμλ₯Ό λͺ¨λ 맀κ°λ³μμ μΆκ°ν΄μ£Όλ λ©μλ
public void clone(Collection<? super T> out) {
for (Object elem : element) {
out.add((T) elem);
}
}
}
in / out 곡μ
μ€λΌν΄ 곡μ λ¬Έμμμλ PECS λμ in κ³Ό out μ κ°λ μΌλ‘ μμΌλμΉ΄λ μ¬μ©μ²λ₯Ό μ€λͺ νλ€.
μμ μμ μμλ in κ³Ό out λ°©λ²μ μ¬μ©νλλ°, extends μμ 맀κ°λ³μλͺ μ΄ in μ΄κ³ , super μμ 맀κ°λ³μλͺ μ΄ out μΈκ±Έ νμΈ ν μ μλ€. μ΄λ₯Ό ν©μΉλ©΄ μλμ κ°μ΄ μ 리ν μ μλ€.
- in λ³μλ μ½λμ 볡μ¬ν λ°μ΄ν°λ₯Ό μ κ³΅μ΄ λͺ©μ → extends
- out λ³μλ λ€λ₯Έ κ³³μμ μ¬μ©ν λ°μ΄ν°λ₯Ό 보μ → super
public static <E> void copyList(List<? extends E> in, List<? super E> out) {
for(E elem : in) {
out.add(elem);
}
}
μμ μμΌλμΉ΄λμ μ μ½ ννΈμμ λ°°μ λ―μ΄, extends λ μ μ΄μ μμ setμ λͺ»νκ³ μ€λ‘μ§ get λ§ κ°λ₯νλ€. λ°λΌμ μ λ€λ¦ νμ 맀κ°λ³μμ λ°μ΄ν°λ₯Ό κ°μ Έμ€λ μν μ νλ©΄ μν κ²½κ³ μμΌλμΉ΄λ λ₯Ό μ¬μ©νλ€κ³ 보면 λλ€.
superμ μ μ΄μ μμ getμ Objectλ‘ κ°μ Έμ€λ μλ―Έκ° μλ€κ³ 보면λκ³ , κ·Έλ¬λ©΄ μ€λ‘μ§ set λ§ κ°λ₯νλ€. λ°λΌμ μ λ€λ¦ νμ 맀κ°λ³μμ λ°μ΄ν°μ μ μ¬νλ μν μ νλ©΄ νν κ²½κ³ μμΌλμΉ΄λ λ₯Ό μ¬μ©νλ€κ³ 보면 λλ€.
νΌλν μ μλ μμΌλμΉ΄λ νν
μμΌλμΉ΄λλ μ€κ³κ° μλ μ¬μ©μ μν κ²
μλ΄κΈ° κ°λ°μλΆλ€μ΄ κ°μ₯ λ§μ΄ μ°©κ°νλ κ²μ΄ μμΌλμΉ΄λλ₯Ό μ΄λμλ μ¬μ©ν μ μλ€κ³ μκ°νλ κ²μ΄λ€. νμ§λ§ μμΌλμΉ΄λλ μλμ κ°μ΄ ν΄λμ€λ μΈν°νμ΄μ€ μ λ€λ¦μ μ€κ³ν λλ μμ μ¬μ©ν μκ° μλ€.
class Sample<? extends T> { // ! Error
}
μμΌλμΉ΄λλ μ΄λ―Έ λ§λ€μ΄μ§ μ λ€λ¦ ν΄λμ€λ λ©μλλ₯Ό μ¬μ©ν λ μ΄μ©νλ κ²μΌλ‘ 보면 λλ€. μλ₯Όλ€μ΄ λ€μκ³Ό κ°μ΄ λ³μλ 맀κ°λ³μμ μ΄λ ν κ°μ²΄μ νμ νλΌλ―Έν°λ₯Ό λ°μλ κ·Έμ λν λ²μ νμ μ μ ν λ μ¬μ©λλ€κ³ 보면 λλ€.
class Sample<T> {
public static <E> void run(List<? super E> l) {}
}
public class Main {
public static void main(String[] args) {
Sample<?> s2= new Sample<String>();
Sample<? extends Number> s1 = new Sample<Integer>();
Sample.run(new ArrayList<>());
}
}
<T extends νμ > μ <? extends U> μ°¨μ΄μ
λ°λ‘ μμμ μΈκΈνλ―μ΄, μμΌλ μΉ΄λλ μ λ€λ¦ ν΄λμ€λ₯Ό λ§λ€λ μ¬μ©νλ κ²μ΄ μλλΌ, μ΄λ―Έ λ§λ€μ΄μ§ μ λ€λ¦ ν΄λμ€λ₯Ό μ¬μ©ν λ νμ μ μ§μ ν λ μ΄μ©λλ κ²μ΄λ€.
μ¦, <T extends νμ
> λ μ λ€λ¦ ν΄λμ€λ₯Ό μ€κ³ν λ μ μ΄μ£Όλ κ²μ΄κ³ , <? extends νμ
> λ μ΄λ―Έ λ§λ€μ΄μ§ μ λ€λ¦ ν΄λμ€λ₯Ό μΈμ€ν΄μ€ν νμ¬ μ¬μ©ν λ νμ
νλΌλ―Έν°λ‘ λ겨μ€λ μ μ΄μ£Όλ κ²μ΄λ€.
<T super νμ > μ μ μμκΉ
μμΌλμΉ΄λμ <T extends νμ
> μ μ‘΄μ¬νμ§λ§, <T super νμ
> μ μλ κ±Έ λ³Ό μ μλ€.
<T extends νμ
> λ μ μν μ λ€λ¦ νμ
λ²μλ₯Ό μν μ ννκΈ° μν΄ μ¬μ©νλλ°, <T super νμ
> μ΄ λλ€λ©΄ 무μν λ§μ μλ°μ ν΄λμ€μ μΈν°νμ΄μ€κ° μ¬ μ μλ€λ λ»μ΄κΈ° λλ¬Έμ, Objectμ λ€λ₯΄μ§ μμ κ·Έλ₯ μΈλͺ¨μλ μ½λμ΄κΈ° λλ¬Έμ΄λ€.
<?> μ <Object> λ λ€λ₯΄λ€
λΉκ²½κ³ μμΌλμΉ΄λκ° λͺ¨λ νμ
μ΄ λ€μ΄μ¬ μ μμΌλ Objectμ λ€λ₯Όλ° μλ€κ³ λ§ν μ μκ² μ§λ§, μλ°ν List<?> μ List<Object> λ λ€λ₯Έ λμ΄λ€. μλνλ©΄ List<Object>μλ Objectμ νμ νμ
μ λͺ¨λ λ£μ μ μμ§λ§, List<?> μλ μ€μ§ nullλ§ λ£μ μ μκΈ° λλ¬Έμ΄λ€. (μ λͺ¨λ₯΄λ©΄ μλ‘ μ¬λΌκ° λ€μ 볡μ΅νμ!)
μ΄λ νμ
μμ μ±μ μ§ν€κΈ° μν μ λ€λ¦μ νΉμ±μΌλ‘, λ§μ½ λ€μκ³Ό κ°μ΄ List<?>μ λͺ¨λ νμ
μ λ£μ μ μκ² νλ€λ©΄, List<Integer>μ Doubleνμ μΆκ°νλ λͺ¨μ λ°μνκ² λμ΄μ κ·Έλ λ€.
public static void main(String[] args) {
List<Integer> ints = new ArrayList<>();
add(ints);
}
private static void add(List<?> ints){
ints.add(3.14); // μΈλΆμμ λ°μ List<Integer>μ Doubleμ μΆκ°νλ λͺ¨μ λ°μ
}
# μ°Έκ³ μλ£
μ΄νν°λΈ μλ° Effective Java 3/E
https://www.youtube.com/watch?v=Vv0PGUxOzq0
https://www.youtube.com/watch?v=w5AKXDBW1gQ