클래스와 마찬가지로 메서드도 제네릭으로 만들수있다
매개변수화 타입을 받는 정적 유틸리티 메서드는 보통 제네릭
Collections의 알고리즘 메서드는 모두 제네릭
컴파일은 되지만 경고가 발생한 경우?
1)메서드 타입을 안전하게 만들어야한다.
->메서드 선언에서의 세집합(입력2개,반환1개)의 원소타입을 타입 매개변수로 명시하고 메서드안에서도 타입 매개변수만 사용하게 하면 됨
public static <E>Set<E> union(Set<E> s1, Set<E> s2){
Set<E> result= new HashSet<>(s1);
result.addAll(s2);
return result;
}
단순한 제네릭메서드
public static void main(String[] args) {
Set<String> guys= Set.of("톰","딕","해리");
Set<String> stooges= Set.of("래리","모에","컬리");
Set<String> aflCio= union(guys,stooges);
System.out.println(aflCio);
//System.out.println("Hello world!");
}
제네릭 메서드를 활용하는 간단한 프로그램
union 메서드는 집합 3개(입력2개,반환1개)의 타입이 모두 같아야한다.
때때로 불변객체를 여러 타입으로 활용할수있게 만들어야할때가있다
제네릭은 런타임에 타입 정보가 소거되므로 하나의객체를 어떤 타입으로든 매개변수화 할수 있다.
->요청한 타입매개변수에 맞게 매번 그 객체의 타입을 바꿔주는 정적 팩터리를 만들어야 한다.
-> 이 패턴을 제네릭 싱글턴 팩터리라 부른다
Collections.reverseOrder같은 함수 객체나
Collections.emptySet과 같은 컬렉션용으로 사용
2)항등함수를 담은 클래스 생성을 가정
제네릭 싱글턴 팩터리패턴
private static UnaryOperator<Object> IDENTITY_FN=(t)->t;
@SuppressWarnings("unchecked")
public static <T> UnaryOperator<T> identityFunction(){
return (UnaryOperator<T>) IDENTITY_FN;
}
항등함수란 입력값을 수정없이 그대로 반환하는 특별한 함수
T가 어떤 타입이든 UnaryOperator< T >를 사용해도 타입은 안전하다.
UnaryOperator < String >과 UnaryOperator < Number >로 사용하는 모습
제네릭 싱글턴을 사용하는 예
public static void main(String [] args){
String [] strings={"삼베","대마","나일론"};
UnaryOperator<String> sameString= identifyFunction();
for(String s: strings)
System.out.println(sameString.apply(s));
Number[] numbers={1,2.0,3L};
UnaryOperator <Number> sameNumber= identifyFunction();
for(Number n: numbers)
System.out.println(sameNumber.apply(n));
}
재귀적 타입한정
주로 타입의 자연적 순서를 정하는 Comprable인터페이스와 함께쓰임
public interface Comaprable<T>{
int compareTo(T o);
}
Comparable을 구현한 원소의 컬렉션을 입력받는 메서드들은
주로 그원소들을 정렬,검색 하거나 최소,최댓값을 구하는 방식으로 사용
다음은 이 제약을 코드로 표현한 모습
public static <E extends Comaprable<E>> E max(Collection<E> c);
타입 한정인 <E extends Comaprable> 는 모든 타입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;
}
핵심정리
1.클라이언트에서 입력매개변수와 반환값을 명시적으로 형변환 해야 하는 메서드보다 제네릭메서드가 더 안전하며 사용하기 쉽다.
2.타입과 마찬가지로 형변환없이 사용할수있는 편이 좋다.
3.형변환을 해줘야하는 기존메서드는 제네릭하게 만드는것이 좋다.
(기존클라이언트는 그대로 둔 채 새로운 사용자의 삶을 훨씬 편하게 만들어줌.)