Collections의 binarySearch, sort 등 알고리즘 메서드는 모두 제네릭이다.public static <T>
int binarySearch(List<? extends Comparable<? super T>> list, T key) {
if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
return Collections.indexedBinarySearch(list, key);
else
return Collections.iteratorBinarySearch(list, key);
}
public static <E> Set<E> union (Set<E> s1, Set<E> s2){
Set<E> result = new HashSet<>(s1);
result.addAll(s2);
return result;
}
위 코드는 세개의 Set 집합이 타입이 모두 같아야 한다.
이를 한정적 와일드 카드 타입을 이용하면 더 유연하게 개선이 가능하다.
컴파일은 되지만 경고가 된다. 타입 안전하지 않기 때문이다.
요청 타입 변수에 맞게 객체의 타입을 바꿔주는 "제네릭싱글턴팩터리" 필요
제네릭 싱글턴 팩터리를 사용하는 예시는
함수객체 Collections.revoerseOrder() 가 있다.
(여기서 함수 객체란?)
이처럼 함수 내부에 들어가는 객체를 함수 객체라고 한다
List<String> str = Arrays.asList("a", "b", "c");
str.sort(Collections.reverseOrder());
불변 객체를 여러 타입으로 활용할 때가 있다.
제네릭은 런타임시 타입 정보가 소거 되므로 하나의 객체를
어떤 타입으로든 매개변수화 할 수 있다.
객체를 매개변수화하려면 요청한 타입 매개변수에 맞게
매번 그 객체의 타입을 바꿔주는 정적 팩터리가 필요할때가 있습니다.
그리하여 이 정적 팩터리를 제네릭 싱글턴 팩터리라고 한다는 것입니다.
private static UnaryOperator<Object> IDENTITY_FN = (t) -> t;
@SuppressWarinings("unchecked")
public static <T> UnaryOperator<T> identityFunction(){
return (UnaryOperator<T>) IDENTITY_FN;
}
항등함수는 입력 값을 수정 없이 그대로 반환하는 특별한 함수이므로
T가 어떤 타입이든 UnaryOperator<T>를 사용해도 타입 안전하다.
재귀적 타입 한정은 자신이 들어간 표현식을 사용하여 타입 매개변수의 허용 범위를 한정하는 개념이다.
이런 재귀적 타입 한정은 주로 타입의 자연적 순서를 지정해주는Comparable과 함께 사용된다.
public interface Comparable<T>{
int compareTo(T o);
}
타입 매개변수 T는 Comparable<T>를 구현한 타입이 비교할 수 있는 원소의 타입을 정의한다.
실제 거의 모든 타입은 자기 자신과 같은 타입만 비교가 가능하다.
String은 Comparable<String>을 구현하고 Integer는 Comparable<Integer>를 구현한다.
Comparable을 구현한 원소의 컬렉션을 입력받는 메서드들은 정렬,
검색등 기능을 수행하는데 이런 기능을 수행하기 위해 컬렉션에 담긴 모든 원소가 상호 비교되어야 한다.
public static <E extends Comparable<E>> E max(Collection<E> c);
<E extends Comparable<E>>가 모든 타입 E는 자신과 비교할 수 있다는 의미를 갖는다.
아래는 재귀적 타입 한정을 이용한 메서드를 구현했다.
컴파일오류나 경고는 발생하지 않으며 컬렉션에 담긴 원소의
자연적 순서를 기준으로 최댓값을 계산한다.
public static <E extends Comparable<E>> E max(Collection<E> c){
if(c.isEmpty()){
throw new IllegalArgumentException("컬렉션이 비었습니다.");
}
E result = null;
for (E e : c){
if(result == null || e.compareTo(result) > 0){
result = Objects.requireNonNull(e);
}
}
return result;
}
제네릭 타입 메서드가 타입 안전하며 사용하기 쉽다.
메서드도 형변환 없이 사용할 수 있는 편이 좋다.
만약 형변환 해야 하는 메서드가 있다면 제네릭하게 만들자.