와일드카드<?>
?의 의미는 알 수 없는 타입이고 모든 타입이 될 수 있음
- 제네릭 타입을 사용하고 싶지만, 들어오는 실제 타입 매개변수가 무엇인지 신경쓰고 싶지 않다면 와일드카드(<?>)를 사용함
제네릭 타입<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 |