- 다양한 타입의 객체들을 다루는 메서드나 컬렉션 클래스에 컴파일 시의 타입 체크(compile-time type check)를 해주는 기능
- 타입 안정성을 높이고 형변환의 번거로움이 줄어든다.
지네릭 클래스
class Box<T> { // 지네릭 타입 T를 선언
T item;
void setItem(T item) { this.item = item; }
T getItem() { return item; }
}
- T 는 타입 변수(type variable)
- Box는 원시 타입(raw type)
제한된 지네릭 클래스
class FruitBox<T extends Fruit> { // Fruit의 자손만 타입으로 지정가능
ArrayList<T> list = new ArrayList<T>();
...
}
class FruitBox<T extends Fruit & Eatable> { ... } // Fruit의 자손이면 Eatable 인터페이스 구현
와일드 카드
- 지네릭 클래스가 다른 메서드의 변수로 쓰일 때
- runtime에 지네릭 클래스의 타입이 정해진다면?
<? extends T> 와일드 카드의 상한 제한. T와 그 자손들만 가능
<? super T> 와일드 카드의 하한 제한. T와 그 조상들만 가능
<?> 제한 없음. 모든 타입이 가능. <? extends Object>와 동일
static <T> void sort(List<T> list, Comparator<? super T> c)
- Comparator에 하한을 제한하는 와일드 카드가 쓰인 이유?
- 만약 Apple 타입으로 지정되어 Apple의 compare 메서드를 구현했을 때, Grape 타입으로는 정렬이 불가능함.
지네릭 메서드
- 지네릭 메서드는 메서드의 선언부에 지네릭 타입이 선언된 메서드이다.
static Juice makeJuice(FruitBox<? extends Fruit> box) { ... }
// 위 메서드를 지네릭 메서드로 바꾸면 다음과 같다.
static <T extends Fruit> Juice makeJuice(FruitBox<T> box) { ... }
// 위 sort 메서드를 다음과 같이 작성할 수 있다.
public static <T extends Comparable<? super T>> void sort<List<T> list)
- 사용 예시
FruitBox<Fruit> fruitBox = new FruitBox<Fruit>();
...
System.out.println(Juicer.<Fruit>makeJuice(fruitBox)); // 대입된 타입을 생략할 수도 있다.