Closed madplay closed 5 years ago
규칙 : 메서드 선언에 타입 매개변수가 한 번만 나오면 와일드카드로 대체하라
public static void swap(List<?> list, int i, int j) { list.set(i, list.set(j, list.get(i))); // error }
- 방금 꺼낸 원소를 리스트에 다시 넣을 수 없어서 에러가 발생하는데 그 이유는 `List<?>에는 null 외에는 어떤 값도 넣을 수 없기 때문
- 그럼 해결책으로 와일드카드 타입의 실제 타입을 알려주는 메서드 구현하라 하였고, 다음과 같은 도우미 메서드를 구현하면 된다고 책에서는 소개함
public static void swap(List<?> list, int i, int j){
swapHelper(list, i, j);
}
private static <E> void swapHelper(List<E> list, int i, int j){
list.set(i, list.set(j, list.get(i)));
}
여기서 swapHelper 메서드는 리스트가 List
여기서 궁금한게... 그럼 처음부터 (1-1의 입력 매개변수에 List<?>가 아닌 List
public static void swap(List<E> list, int i, int j) {
list.set(i, list.set(j, list.get(i)));
}
이런식으로 구현하면 문제 없지 않나요?
혹시 책에서 말하고자 하는 의도가 무엇인지 아시는 분 있다면 설명 부탁드립니다 ( )
그런식으로 해도 문제없습니다. 실제로 와일드카드를 쓰는 대다수의 경우는 타입파라미터를 사용하는쪽으로도 해결이 가능합니다. 그럼 이 두개가 뭔 차이인지를 알아야하는데요.
타입파라미터는 타입을 캡쳐하고 와일드카드는 하지않습니다. 즉 메서드 내부에서 타입을 알아야하는경우는 타입파라미터를 쓰고, 타입을 몰라도 되는경우는 와일드카드를 쓰는걸 권합니다.
가령 List를 받아서 그 size를 리턴하는경우엔 List가 어떤 요소를 담고있든 중요하지않죠. 이럴땐 타입파라미터가 아니라 와일드카드를 권합니다.
그런 관점에서 봤을때 swap은 내부 요소가 어떤건지 알필요가 없습니다. 타입이 어떤거든 상관없이 요소들의 순서를 변경해주는거니까요. 그런데 개념적으로는 와일드카드가 맞는데 실제로 와일드카드로 구현하면 기술적 한계때문에 메서드 구현이 안됩니다. 개념과 기술의 충돌이 발생하는거죠. 이때 그냥 속편하게 기술쪽을 택하면 글쓴분이 말씀하시는것처럼 구현하게되는거고요. 개념을 지키면서 기술의 한계를 넘을때 저렇게 헬퍼 메서드를 만들어서 해결하는겁니다.
책에서 말하고자하는 의도는 '개념적 접근' 입니다. 실제로 Collection 을 사용하시다보면 메서드가 어떤건 타입파라미터로 되어있고 어떤건 와일드카드로 되어있는데 이때 와일드카드로 되어있는건 '아 얘네는 내부타입이 뭐든 신경쓰지않겠구나' 라고 이해하시면 됩니다.
매개변수화 타입은 불공변(invariant) #28
Sub
은Super
의 하위 타입Sub[]
도Super[]
의 하위 타입 -하지만!List<Sub>
은List<Super>
의 하위 타입도, 상위 타입도 아닙니다.<String>
은 List<object>
의 하위 타입이 아니라는 뜻<Object>
에는 어떤 객체든 넣을 수 있지만, List<String>
에는 문자열만 넣을 수 있음.List
<String>
은 List<Object>
가 하는 일을 제대로 수행하지 못하니 하위 타입이 될 수 없음한정적 와일드카드를 사용하자
28 배열보다 리스트를 사용하라고 했음
} }
Stack<Number>
로 선언한 후 pushAll(intVal)을 호출하면 어떻게 될까?Iterable<Integer>
cannot be converted toIterable<Number>
공식 : 팩스(PECS) producer-extends, consumer-super
<? extends T>
<? super T>
... }
Chooser<Number>
의 생성자에List<Integer>
를 매개변수로 넘길 수 있게 됨}
Set<Number>
이다.// 와일드카드 타입 사용 public static <E extends Comparable<? super E>> E max(List<? extends E> list)
Comparable<ScheduledFuture>
를 구현하지 않았기 때문Comparable<Delayed>
를 확장메서드 선언에 타입 매개변수가 한 번만 나오면 와일드카드로 대체하라
// 2. 비한정적 와일드카드 사용 public static void swap(List<?> list, int i, int j);
List<?>
에는 null 외에는 어떤 값도 넣을 수 없기 때문// 와일드카드 타입을 실제 타입으로 바꿔주는 private 도우미 메서드 private static void swapHelper(List list, int i, int j){
list.set(i, list.set(j, list.get(i)));
}