와일드카드 GET / SET 경계
List<? extends U>
결론
GET : 안전하게 꺼내려면 U 타입으로 받아야 한다.
SET : 어떠한 타입의 자료도 넣을 수 없음(null 만 삽입 가능)
꺼낸 타입은 U / 저장은 NO
이유
메서드의 매개변수 제네릭 타입이
<? extends Fruit>라는 것은Apple, Banana, Fruit타입을 전달 받아 내부에서 다룰 수 있다는 점이다.그런데 왜 GET 을 왜 Fruit 로 받아야 하냐면,
만약, 매개변수에
List<Banana>타입으로 들어올 경우,Apple f2에 형제 캐스팅이 불가하기 때문이다.때문에, 이러한 논리 오류로 와일드카드 최상위 범위인
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);
}
}또한, SET 을 어떠한 타입도 불가능하냐면
만일 매개변수에
List<Banana>타입으로 들어올 경우 형제 객체인new Apple()저장이 불가능하기 때문이다.만일 매개변수에
List<Fruit>타입으로 들어올 경우 문제는 없겠지만, 위의 논리 오류로 그냥 컴파일 에러로 처리된다.따라서 만일 매개변수에 값을 넣고 싶다면 무조건
super와일드카드를 사용해야 한다.
List<? super U>
결론
GET : 안전하게 꺼내려면 Object 타입으로만 받아야 한다.
SET : U와 U의 자손 타입만 넣을 수 있다.(U의 상위 타입 불가능)
꺼낸 타입은 Object / 저장은 U 와 그의 자손만
이유
메서드의 매개변수의 제네릭 타입이
<? super Fruit>라는 것은Fruit, Food, Object타입을 전달 받아 내부에서 다룰 수 있다는 것이다.그런데 왜 GET 을
Object타입으로 받아야 되냐면,만일 매개변수에
List<Food>타입이 들어올 경우Fruit f3에 캐스팅이 불가하기 때문이다.이러한 논리 오류로 와일드카드 최상위 범위인
Object타입으로만 안전하게 꺼낼 수 있는 것이다.
또한, SET 을 거꾸로 Fruit 와 그의 자손 타입만 올 수 있냐면,
만일 매개변수에
List<Fruit>타입으로 들어올 경우new Food()저장이 불가능하기 때문이다.따라서 어떠한 타입이 와도 업캐스팅이 가능 상한인
Fruit타입으로만 제한된다.
List<?>
결론
GET : 안전하게 꺼내려면 Object 타입으로만 받아야 한다. -> super 의 특징
비제한 와일드카드는 어떤 타입이 들어올지 모르기 때문에, 최상위 타입인 Object 로 받아야 한다.
SET : 어떠한 타입의 자료도 넣을 수 없음(null 만 삽입 가능) -> extends 의 특징
넣어야 하는 타입이 정해지지 않았는데? 값을 넣을수가 있나?
꺼낸 타입은 Object / 저장은 NO
이유
Last updated