와일드카드<?>
?의 의미는 알 수 없는 타입이고 모든 타입이 될 수 있음
- 제네릭 타입을 사용하고 싶지만, 들어오는 실제 타입 매개변수가 무엇인지 신경쓰고 싶지 않다면 와일드카드(<?>)를 사용함
제네릭 타입<T>와 와일드 카드<?>의 차이
- 제네릭 : 타입을 모르지만, 타입이 정해지면 그 타입의 특성에 맞게 사용함
- 와일드 카드 : 무슨 타입인지 모르고, 무슨 타입인지 신경쓰지 않음. 타입을 확정하지 않고 가능성을 열어둠
interface Drink{ } class Coffee implements Drink{ } class Milk implements Drink{ } public class GenericTest { private void test1(final List<? extends Drink> drinks ){ final Drink drink = drinks.get(0); // <? extends Drink>에 들어가는 타입은 Drink가 될수도, Drink를 구현한 Coffee가 될수도 Milk가 될수도 있다. // 하지만 결국 Drink 타입을 구현하므로 drinks에서 꺼내오는 것은 Drink 타입이 된다. Drink drink1 = new Coffee(); drinks.add(drink1); // ⚡ 컴파일오류 // <? extends Drink>가 Drink 타입임을 확신할 수 없다. drinks에 넣을수 없다. } private <T extends Drink> void test2(final List<T> drinks){ final T t = drinks.get(0); // <T extends Drink>에 들어가는 타입은 Drink가 될수도, Drink를 구현한 Coffee가 될수도 Milk가 될수도 있다. // 하지만 결국 Drink 타입을 구현하므로 Drink 타입이 될 수 있다. drinks.add(drinks.get(0)); //정상 작동 // T라는 제네릭타입은 입력받는 순간 정해지고 그 타입으로 고정되므로 문제없이 추가된다. } }
상하 제한과 하한 제한에서의 와일드카드 차이점
private void test1(final List<? extends Drink> drinks) { final Drink drink = drinks.get(0); // <? extends Drink> 여기에 들어가는 타입은 Drink가 될수도, Drink를 구현한 Coffee가 될수도 Milk가 될수도 있다. // 하지만 결국 Drink 타입을 구현하므로 drinks에서 꺼내오는 것은 Drink 타입이 된다. Drink drink1 = new Coffee(); drinks.add(drink1); // ⚡ 컴파일오류 // 와일드카드는 무슨 타입인지 신경쓰지 않는다. // 따라서 <? extends Drink>가 Drink 타입임을 확신할 수 없다. // List<Coffee>일수도 List<Drink> 일수도 있다. 따라서 drinks에 넣을수 없다. } private void test3(final List<? super Drink> drinks) { final Object object = drinks.get(0); // Drink의 부모만 오기 때문에 모든 것을 포괄하는 Object 타입이 된다. (사실상 타입을 알 수 없는 것과 같다) Drink drink1 = new Coffee(); drinks.add(drink1); // 정상 작동 // Object 타입으로 변경될 것이고 특정 타입이 아닌 Object 타입이 되므로 drinks에 넣을수 있다. // 하지만 들어가는 것은 Drink의 하위 타입이어야 한다. 왜냐면 Drink 상위타입 어떤 것이 될 수 있는 가능성이 있기 때문이다. }
'CS 지식 > [자료구조]' 카테고리의 다른 글
[자료구조] DFS & BFS (1) | 2023.10.20 |
---|---|
[자료구조] 제네릭(generic) (0) | 2023.10.20 |
[자료구조] 빅오 표기법(big-O notation) (1) | 2023.10.20 |
[자료구조] 자료구조 (1) | 2023.10.20 |
[자료구조] HashMap (0) | 2023.08.01 |