클래스와 인터페이스 선언에 타입 매개변수가 쓰이면 제네릭 클래스
혹은 제네릭 인터페이스
라고 하며, 두 가지를 통틀어 제네릭 타입
(generic type)이라고 한다.
로 타입
(raw type)이란 타입 매개변수가 없는 제네릭 타입을 말한다. 예를 들어, List<E>의 로 타입은 List
다.
로 타입은 타입 선언에서 제네릭 타입 정보를 전부 지워진 것처럼 동작하는데, 제네릭이 도래하기 전 코드와 호환되도록 하기 위한 궁여지책이라 할 수 있다.
컬렉션 로 타입을 사용할 경우, 엉뚱한 타입을 넣어도 오류 없이 컴파일되고 실행될 수 있다.
이 경우, 형변환 시 ClassCastException
을 던지게 된다.
📍 컬렉션의 로 타입 → 좋지 않은 예!
private final Collection stamps = ...;
...
stamps.add(new Coin(...)); // 실수로 동전을 넣는다.
...
for(Iterator i = stamps.iterator(); i.hasNext();) {
Stamp stamp = (Stamp) i.next(); // ClassCastException을 던진다.
stamp.cancel();
}
📍 매개변수화된 컬렉션 타입 → 타입 안전성 확보!
다음과 같이 선언하면, 컴파일러는 엉뚱한 타입의 인스턴스를 넣으려고 할 때 오류를 발생시킨다.
private final Collection<Stamp> stamps = ...;
'로 타입을 쓰면 제네릭이 안겨주는 안전성과 표현력을 모두 잃게된다'는 점을 기억하자!
📍 매개변수화 타입 → 타입 안전성!
List
와 같은 로 타입은 사용해서는 안 되지만, List<Object>
와 같은 임의 객체를 허용하는 매개변수화 타입은 괜찮다.
매개변수화 타입은 컴파일러에게 모든 타입을 허용한다는 의사를 명확히 전달한 것이다.
📍 비한정적 와일드카드 타입 → 타입 안전하며 유연!
제네릭 타입을 쓰고 싶지만, 실제 타입 매개변수가 무엇인지 신경쓰고 싶지 않을 때는 비한정적 와일드 카드 타입을 사용하자.
비한정적 와일드 카드는 물음표(?
)를 사용하면 된다.
예를 들어, Set<?>
, Collection<?>
이런 식이다.
class 리터럴
에는 로 타입을 써야 한다.
List.class
, String[].class
, int.class
(O)List<String>.class
, List<?>.class
(X)instanceof
연산자는 로 타입을 써도 좋다.
if(o instanceof Set) { // 로 타입
Set<?> s = (Set<?>) o;
...
}
한글 용어 | 영문 용어 | 예 | 아이템 |
---|---|---|---|
매개변수화 타입 | parameterized type | List<String> | 아이템 26 |
실제 타입 매개변수 | actual type parameter | String | 아이템 26 |
제네릭 타입 | generic type | List<E> | 아이템 26, 29 |
정규 타입 매개변수 | formal type parameter | E | 아이템 26 |
비한정적 와일드카드 타입 | unbounded wildcard type | List<?> | 아이템 26 |
로 타입 | raw type | List | 아이템 26 |
한정적 타입 매개변수 | bounded type parameter | <E extends Number> | 아이템 29 |
재귀적 타입 한정 | recursive type bound | <T extends Comparable<T>> | 아이템 30 |
한정적 와일드카드 타입 | bounded wildcard type | List<? extends Number> | 아이템 31 |
제네릭 메서드 | generic method | static <E> List<E> as List(E[] a) | 아이템 30 |
타입 토큰 | type token | String.class | 아이템 33 |
📌 핵심 정리
- 로 타입을 사용하면 런타임에 예외가 발생할 수 있으니 사용하면 안 된다.
- 로 타입은 제네릭이 도입되기 이전 코드와의 호환성을 위해 제공될 뿐이다.
- 매개변수화 타입:
Set<Object>
, 어떤 타입의 객체도 저장할 수 있다.
와일드카드 타입:Set<?>
, 모종의 타입 객체만 저장할 수 있다.
로 타입:Set
Set<Object>
와Set<?>
는 안전하지만, Set은 안전하지 않다.