Generic

  • 타입을 매개변수화한 것
  • 클래스 혹은 메소드에 선언 가능
  • 동시에 여러 타입 선언 가능

A Simple Box Class

public class Box {
    private Object object;

    public void set(Object object) {
        this.object = object;
    }

    public Object get() {
        return object;
    }
}
  • 컴파일 시 클래스가 어떻게 사용되는지 확인할 방법이 없다.
  • 타입 안정성 부족
Box box = new Box();
box.set(123); // Integer 값을 box에 저장
box.set("hello"); // 실수로 String 값을 box에 저장
Integer value = (Integer) box.get(); // 여기서 ClassCastException 발생

A Generic Version of the Box Class

public class Box<T> {
    // T stands for "Type"
    private T t;

    public void set(T t) {
        this.t = t;
    }

    public T get() {
        return t;
    }
}
  • 모든 Object를 T로 변경
  • 파라미터 타입이나 리턴 타입에 대한 정의를 외부로 미룬다.
  • 타입에 대해 유연성과 안정성을 확보
  • 타입을 유연하게 처리하며, 런타임에 발생할 수 있는 타입에러를 컴파일 전에 검출
  • 제네릭 파라미터에 의해 타입이 고정되기 때문에 안정성 확보

  • static 멤버에 타입 변수 T를 사용할 수 없다. T는 인스턴스 변수로 간주되기 때문이다.
class Box<T> {
    static T item; // Error!
    static int compare(T t1, T t2) {} // Error!
}
  • 제네릭 타입의 배열을 생성하는 것이 허용되지 않는다.
class Box<T> {
    T[] items; // OK
    T[] items = new T[3]; // Error!
}

Wildcard

  • <?> 이것의 명칭을 와일드카드라 한다.
  • 어떤 타입이든 될 수 있다는 뜻
  • 제네릭의 한계를 보완한 것이라 생각하면 이해가 쉽다.
  • <?>
    • 제한 없음. 모든 타입 가능
    • <? extends Object>와 동일
  • <? extends T>
    • 와일드카드의 상한 제한
    • T와 그 자손들만 가능
  • <? super T>
    • 와일드카드의 하한 제한
    • T와 그 조상들만 가능

Generic method

class FruitBox<T> {
    static <T> void sort(List<T> list, Comparator<? super T> c) {}
}
  • 메서드의 선언부에 제네릭 타입이 선언된 메서드를 제네릭 메서드라 한다.
  • 제네릭 클래스에 정의된 타입 매개변수와 제네릭 메서드에 정의된 타입 매개변수는 완전 별개의 것이다.
    • 문자 T만 같은 것을 쓰는 것이지 같은 타입은 아니다.
  • 메서드에 선언된 제네릭 타입은 지역 변수를 선언한 것과 같다고 생각하면 된다.
    • 매개변수에 선언할 타입 T에 대한 자료형을 미리 선언해 주기 때문에 static 메서드에서 타입 매개변수 T의 사용을 가능하게 해 주는 것이다.

Collections의 sort() 메서드

public static <T extends Comparable<? super T>> void sort(List<T> list)
  • 타입 T를 요소로 하는 매개변수를 허용하되
  • T는 Comparable을 구현한 클래스여야 하며 T 또는 그 조상의 타입을 비교하는 Comparable이어야 한다.
  • 만약 T가 Student이고 Person의 자손이라면 <? super T>Student, Person, Object가 가능하다.

참고1
참고2
참고3