로 타입
- 로 타입이란 제네릭 타입 매개변수를 전혀 사용하지 않을 때를 말한다.
- 예컨대
List<E>
의 로 타입은 List다.
- 예컨대
- 로 타입(타입 매개변수가 없는 제네릭 타입)을 쓰는 걸 언어 차원에서 막아 놓진 않았지만 절대로 써선 안된다.
- 로 타입을 쓰면 제네릭을 안겨주는 안정성과 표현력을 모두 잃게 된다.
- 그럼에도 불구하고 로 타입이 생긴 이유는 제네릭 타입이 없을때 작성된 코드들과의 하위 호완성을 유지하기 위해서이다.
로 타입인 List와 매개변수화 타입인 List
List
는 제네릭 타입에서 완전히 발을 뺀 것이고,List<Object>
는 모든 타입을 허용한다는 의사를 컴파일러에게 명확히 전달한 것이다.- 즉,
List<String>
은 로 타입인 List의 하위 타입이지만,List<Object>
의 하위 타입은 아니다. - 그 결과,
List<Object>
같은 매개변수화 타입을 사용할때와 달리 List와 같은 로타입을 사용하면 타입 안정성을 잃게 된다.(코드 26-4 예제 참고)
1
2
3
4
5
6
7
8
9
10
11
12
// 코드 26-4 런타임에 실패한다. - unsafeAdd 메서드가 로 타입(List)을 사용 (156-157쪽)
public class Raw {
public static void main(String[] args) {
List<String> strings = new ArrayList<>();
unsafeAdd(strings, Integer.valueOf(42));
String s = strings.get(0); // 컴파일러가 자동으로 형변환 코드를 넣어준다. 런타임시 형변환을 실행하려 할때 ClassCastException 이 발생한다!!!
}
private static void unsafeAdd(List list, Object o) {
list.add(o);
}
}
제네릭 타입을 쓰고 싶지만 실제 타입 매개변수가 무엇인지 신경쓰고 싶지 않다면 물음표(?)를 사용하자.
- 예컨대 제네릭 타입인
Set<E>
의 비한정적 와일드 카드 타입은Set<?>
이다. - 어떤 타입이라도 담을 수 있는 가장 범용적인 매개변수화 Set 타입이다.
비한정적 와일드카드 타입인 Set<?>와 로 타입인 Set의 차이는?
- 와일드 카드 타입은 안전하고, 로 타입은 안전하지 않다.
- 와일드 카드 타입
Collection<?>
에는 (null 외에는) 어떤 원소도 넣을 수 없다.
로 타입을 쓰지 말라는 규칙에도 소소한 예외가 몇 개 있다.
- 첫 번째는 class 리터럴에는 로 타입을 써야한다.
- 자바 명세는 class 리터럴에 매개변수화 타입을 사용하지 못하게 했다.(배열과 기본 타입은 허용한다.)
- 예를 들어,
List.class
,String[].class
,int.class
는 허용하고List<String>.class
,List<?>.class
는 허용하지 않는다.
- 두 번째는 런타임에는 제네릭 타입 정보가 지워지므로 instanceof 연산자는 비한정적 와일드카드 타입 이외의 매개변수화 타입에는 적용할 수 없다.
핵심 정리: 로 타입을 사욯아면 런타임에 예외가 일어날 수 있으니 사용해선 안된다. 로 타입은 제네릭이 도입되기 이전 코드와의 호환성을 위해 제공될 뿐이다.
Set<Object>
는 어떤 타입의 객체도 저장할 수 있는 매개변수화 타입이고,Set<?>
는 모종의 타입 객체만 저장할 수 있는 와일드카드 타입이다. 그리고 이들의 로타입인 Set은 제네릭 타입 시스템에 속하지 않는다.Set<Object>
와Set<?>
는 안전하지만, 로타입인Set
은 안전하지 않다.