<>(제너릭, 꺽쇠, 다이아몬드) 라고 불린다.
제네릭 안에 C++의템플릿 처럼 T or E 등 타입을 변수로 선언.
타입이 변수로 선언되기에 타입에 상당히 유연해진다.
컴파일 타임에 타입 검사
➡️ 예외 방지
불필요한 캐스팅 제거
제네릭 타입의 객체는 생성 불가
static 멤버에 제네릭 타입이 올 수 없음
public static T add(int n){ }
public static void add(T n){ }
// error
제네릭 외에도 타입을 Object로 사용하는 방법도 있지만 객체를 호출할 때 번거로움이 생길 수 있다.
제네릭은 불공변이기 때문에 모든 타입에서 공통적으로 사용되는 메서드를 만들기 어려웠다.
Integer는 Object의 하위 타입이지만 List<Integer>는 List<Object>의 하위타입이 아니기 때문
그렇기 때문에 아래와 같은 와일드 카드가 등장하였다.
| 와일드 카드 | 네이밍 | 설명 |
|---|---|---|
<?> |
Unbounded | 제한없음 (모든 타입 가능) |
<? extends U> |
Upper bounded | 상위 클래스 제한 (U와 그 자손들만 가능) |
<? super U> |
Lower bounded | 하위 클래스 제한 (U와 그 조상들만 가능) |
이에 대해 이해하려면 우선 공변성에 대해 알아야한다.
하위 타입이 상위 타입을 참조 가능
S 가 T 의 하위 타입이면,
S[] 는 T[] 의 하위 타입이다.
List<S> 는 List<T> 의 하위 타입이다.
Integer[] intArray = {1, 2, 3};
Object[] objArray = intArray; // 공변성: Integer[]는 Object[]로 변환 가능
List<? extends Number> numberList = new ArrayList<Integer>(); // Integer는 Number의 하위 타입
상위 타입이 하위 타입을 참조 가능
S 가 T의 하위 타입이면,
T[] 는 S[] 의 하위 타입이다. (공변의 반대)
List<T> 는 List<S> 의 하위 타입이다. (공변의 반대)
List<? super Integer> superList = new ArrayList<Number>(); // Number는 Integer의 상위 타입
상/하위 타입 여하를 떠나 참조가 불가함.
S 와 T 는 서로 관계가 없다.
List<S> 와 List<T> 는 서로 다른 타입이다.
List<Number> numberList = new ArrayList<Integer>(); // 컴파일 에러
제너릭은 공변성 / 반공변성을 지원하지 않는다! 즉, 무공변의 성질을 지닌다.
그러므로 제너릭은 전달받은 타입으로만 캐스팅이 가능하다.
| 개념 | 설명 | 예시 |
|---|---|---|
| 공변 | 하위 타입이 상위 타입을 참조 가능 | 배열 (Integer[] -> Object[]), List<? extends Number> |
| 반공변 | 상위 타입이 하위 타입을 참조 가능 | List<? super Integer> |
| 불공변 | 상위 타입과 하위 타입이 참조 불가 | List<Number>와 List<Integer>는 서로 참조 불가 |