- java5 부터 사용할 수 있다.
- 컬렉션이 담을 수 있는 타입을 컴파일러에 미리 알려줄 수 있다.
그래서 컴파일러는 알아서 형변환 코드를 추가할 수 있게 되고, 엉뚱한 타입의 객체를 넣으려는 시도를 컴파일 과정에서 차단하여 더 안전하고 명확한 프로그램을 만들어 준다.
용어 정리 : 클래스와 인터페이스 선언에 타입 매개변수가 쓰이면, 이를 제네릭 클래스 혹은 제네릭 인터페이스라 한다. ex) List -> List 라고도 자주 사용함.
제네릭 타입 = 제네릭 클래스 + 제네릭 인터페이스.
각각의 제네릭 타입은 일련의 매개변수화 타입을 정의한다.
-> 먼저 클래스 이름이 나오고, 이어서 꺾쇠괄호 안에 실제 타입 매개변수들을 나열한다.
-> 제네릭 타입을 하나 정의하면 그에 딸린 로 타입도 함께 정의된다.
-> 로 타입이란 제네릭 타입에서 타입 매개변수를 전혀 사용하지 않을 때를 말한다.
제네릭 지원 전에 컬렉션을 다음과 같이 사용했다.(따라하지 말것!)
// Stamp 인스턴스만 취급한다.
private final Collection stamps = ...;
// 실수로 동전을 넣는다.
stamps.add(new Coin(...)); // "unchecked call"경고를 내뱉는다.
// 컬렉션에서 이 동전을 다시 꺼내기 전에는 오류를 알아채지 못한다.
// 반복자의 로 타입 (따라 하지 말것! - 컴파일 시점이 아닌 런타임때 발견됨)
for (Iterator i = stamps.iterator(); i.hasNext(); ){
// 인스턴스가 스탬프가아닌 코인이기 때문에 ClassCastException을 던진다.
Stamp stamp = (Stamp) i.next();
stamp.cancel();
}
// 매개변수화된 컬렉션 타입으로 타입 안정성(type safety)을 확보하자!
// 코인을 넣을경우 컴파일 단계에서 체크 가능!
private final Collection<Stamp> stamps = ...;
// 제네릭 타입을 쓰고 싶지만 실제 타입 매개변수가 무엇인지 신경 쓰고 싶지 않다면 물음표(?)를 사용하자.
// 비한정적 와일드 카드 타입을 사용할 경우 타입 안전하며 유연하다.
static int numElementsIncommon(Set<?> s1, Set<?> s2){ ... }
BUT 예외로 class 리터럴에는 로 타입을 써야 한다!
자바 명세는 class 리터럴에 매개변수화 타입을 사용하지 못하게 했다.
* 핵심 정리
로 타입을 사용하면 런타임에 예외가 일어날 수 있으니 사용하면 안 된다.
로 타입은 제네릭이 도입되기 이전 코드와의 호환성을 위해 제공될 뿐이다.
빠르게 훑어보자면, Set<Object>는 어떤 타입의 객체도 저장할 수 있는 매개변수화 타입이고,
Set<?>는 모종의 타입 객체만 저장할 수 있는 와일드카드 타입이다. 그리고 이들의 로 타입인 Set은 제네릭
타입 시스템에 속하지 않는다. Set<Object>와 Set<?>는 안전하지만, 로 타입인 Set은 안전하지 않다.