한정적 와일드카드를 사용해 API유연성을 높이라
매개변수화 타입은 불공변
와일드카드 타입을 사용하지 않은 메서드- 결함이있음
public void pushAll(Iterable<E> src){
for(E e:src){
push(e);
}
}
이 메서드는 깨끗하지만 컴파일이 완벽하지않다.
src원소 타입이 스택의 원소타입과 일치하면 동작
여기서 Stack로 선언후에 호출을 하게되면?
Stack<Number> numberStack= new Stack<>();
Iterable<Integer> integers=,,,;
numberStack.pushAll(integers);
논리적으로는 잘 동작해야하지만 오류 메세지가뜨고,
오류가 발생하는 이유는 매개변수화 타입이 불공변이기때문
-> 한정적 와일드카드를 쓰면 해결가능
popAll메서드를 사용할때도 동일하게 쓰면 가능하다.
팩스 (PECS) producer-extends, consumer-super
->즉 매개변수화 타입T가 생산자라면 <? extends T>를 사용하고,소비지라면 <? super T>를 사용
와일드 카드타입을 사용하는 기본원칙
해당공식을 기억하고 앞 아이템들에서 소개한 메서드,생성자선언을 다시살펴보면?
public Chooser(Collection<T> choices)
1)choice컬렉션은 T타입의 값을 생산하기만 하니, 와일드카드 타입을 사용해 선언해야한다.
public Chooser(Collection<? extends T> choices)
제대로만 사용한다면 사용자는 와일드카드타입이 쓰였다는 사실을 의식하지못함
클래스 사용자가 와일드카드 타입을 신경써야한다면 API에 무슨 문제가 있을 가능성이 크다.
2.타입 매개변수와 와일드카드에는 공통된 부분이있어,메서드를 정의할때 둘중 어느것을 사용해도 괜찮을때가 있다.
ex)주어진 리스트에서 명시한 두 인덱스의 아이템을 swap하는 정적메서드를 두방식 모두로 정의
1)비한정적 타입 매개변수
public static <E> void swap(List<E> list,int i,int j);
2)비한정적 와일드카드
public static void swap(List<?> list,int i,int j);
메서드 선언에 타입 매개변수가 한번만 나오면 와일드 카드로 대체
->비한정적 타입 매개변수라면 비한정적 와일드카드로 바꾸고,
한정적 타입매개변수라면 한정적 와일드카드로 바꾸면 된다.
두번째 swap선언에는 문제가 있다
직관적으로 구현한 코드가 컴파일 되지않음
-->형변환이나 리스트의 로 타입을 사용하지않고 해결할수있는 방법이있다.
-->private 도우미 메서드로 따로 작성하여 활용
도우미 메서드는 제네릭 메서드여아함.
private static<E> void swapHelper(List<E> list, int i,int j){
list.set(i, list.set(j,list.get(i)));
}
swapHelper메서드는 리스트가 List임을 알고있다.
값의 타입은 항상 E, E타입의값이라면 리스트에 넣어도 안전하다.
핵심정리
1)조금복잡하더라도 와일드카드 타입을 적용하면 API가 훨씬 유연해진다.
-->널리 쓰일 라이브러리를 작성한다면 와일드카드 타입을 적절히 사용해줘야한다.
2)PECS공식을 기억하자.