매개타입과 리턴타입으로 타입 파라미터를 갖는 메소드.
리턴타입 앞에 < > 기호 추가하고, 타입 파라미터 기술.
public void set(T t){ ;; }
위의 메소드는 리턴타입 앞에 < > 없으므로 제네릭메소드라고 할 수 없다. 제네릭 클래스를 매개변수로 받는 인스턴스 메소드임.
public <T> void set (T t){ ;; }
이처럼 타입파라미터를 기술해주어야 제네릭메소드가 된다.
제네릭 타입일지라도 제네릭메소드는 있을수도 있고, 없을수도 있다.
public class BoxingMethodEx {
public static void main(String[] args) {
//Util.boxing 메소드는 Generic method이기 때문에
//이 메소드를 호출할 때(=사용할때) 는 타입파라미터에 **구체타입**을 지정해서 호출해야 함.
Box<Integer> box1 = Util.<Integer>boxing(100); // 구체타입으로 Integer 지정
int intValue = box1.get(); // 따라서 box1의 값을 intValue로 받을 수 있음.
//위 코드는 아래와 같음
// Box box1 = Util.boxing(100);
// int intValue = (int)box1.get();
///////////////////////
Box<String> box2 = Util.boxing("홍길동"); //<Integer>를 생략하면 타입추론 발생. 타입추론은 Lvalue가 아니라, Rvalue의 매개변수값을 보고 추론함
// >>하지만 제네릭메소드 사용법 익숙해질때까진 생략하지 말 것
String strValue = box2.get();
} //main
} //end class
보통 현실세계의 객체를 모델링해서 만든 클래스가 아니라,
여러 도움이 될만한 기능을제공하는 목적으로 만든 클래스를 의미함.
public class Util {
//타입 파라미터 T를 가지고 있으므로 제네릭 메소드임.
public static<T> Box<T> boxing(T t){
Box<T> box = new Box<T>();
box.set(t);
return box;
} //boxing
} //end class
타입 파라미터 <T>
에 지정 가능한 구체타입을 제한하고 싶을 때 사용 (마치 Enum 타입처럼!)
extends 관계를 이용해 타입을 제한할 수 있다.
public <T extends 상위타입> 리턴타입 메소드(매개변수, ...) { ;; }
상위타입은 클래스 뿐만 아니라 인터페이스도 가능하지만,
그렇다고 implements 키워드를 사용하지는 않는다.
키워드는 무조건 extends임.
상위타입이거나, 상위타입을 extends하는 타입만 <T>
의 구체타입으로 지정할 수 있다.(하위타입에만 있는 필드, 메소드는 사용할 수 없음)
상위타입 확인하려면 OpenTypeHierchy
public class Util {
//타입파라미터 T에 지정가능한 구체타입의 범위를 제약 >> extends 키워드 사용
//<T extends 부모타입> : 지정가능한 구체타입은, 부모타입이거나 / 부모타입을 상속받는 자식타입만 가능
public static <T extends Number> int compare(T t1, T t2){
double v1 = t1.doubleValue();
//log.info(t1.getClass().getName());
double v2 = t2.doubleValue();
return Double.compare(v1, v2);
} //compare
} //end class
public class CompareMethodEx {
public static void main(String[] args) {
//Generic Type Pair 객체를 2개 생성(사용) >> 이 때 구체타입 지정(K, V)
//Pair(K, V> : K ==> key 필드의 타입, V ==> value 필드의 타입
//그런데 우리가 배웠다시피 구체타입 지정할때 Lvalue와 Rvalue
//양쪽에 두 번 지정할 필요 없음 >> Rvalue 구체타입은 생략!
// Pair<Integer, String> p1 = new Pair<Integer, String>(1, "사과");
// Pair<Integer, String> p2 = new Pair<Integer, String>(1, "사과");
Pair<Integer, String> p1 = new Pair<>(1, "사과"); //타입추론
Pair<Integer, String> p2 = new Pair<>(1, "사과"); //타입추론
//Generic Method호출(사용) >> 이 때 구체타입 지정
boolean result1 = Util.<Integer, String>compare(p1, p2);
if(result1) {
log.info("논리적으로 동등한 객체입니다.");
} else {
log.info("논리적으로 동등하지 않은 객체입니다.");
} //if-else
//////////////////////////////////////////
Pair<String, String> p3 = new Pair<String, String>("user1", "홍길동");
Pair<String, String> p4 = new Pair<String, String>("user2", "홍길동");
boolean result2 = Util./*<K,V>*/compare(p1, p2); //타입추론
//구체타입을 생략할 때,
//제네릭 *객체 생성*시에는 <> 다이아몬드 남겨놓고, 제네릭 *메소드 사용*시에는 <> 다이아몬드 기호까지 같이 생략함.
if(result1) {
log.info("논리적으로 동등한 객체입니다.");
} else {
log.info("논리적으로 동등하지 않은 객체입니다.");
} //if-else
} //main
} //end class
구체타입 생략할 때,
제네릭 객체 생성시에는 <> 다이아몬드기호 남겨놓고
제네릭 메소드 사용시에는 <> 다이아몬드 기호까지 같이 생략한다.
정렬 알고리즘 구현할 때 많이 사용함!
기본타입의 wrapper타입에서 모두 사용할 수 있음
compare(value1, value2) 메소드는
두 값을 비교해서, 비교 결과를 아래와 같이 반환한다.
자료구조에서 다시 다룰것임!