아래와 같이 선언하면 stamps에 Stamp의 인스턴스만 넣어야 함을 컴파일러가 인지하게 된다.
privatefinalCollection<Stamp> stamps = ...;
stamps에 엉뚱한 타입의 인스턴스를 넣으려 하면 컴파일 오류가 발생하며 무엇이 잘못됐는지를 정확히 알려준다.
컴파일러는 컬렉션에서 원소를 꺼내는 모든 곳에 보이지 않는 형변환을 추가하여 절대 실패하지 않음을 보장한다.
Test.java:9: error: incompatible types: Coin cannot be converted to Stamp
stamps.add(new Coin());
^
로 타입은 절대 써서는 안된다.
로 타입은 제네릭 이전 코드와의 호환성을 위해 남겨놓은 것일 뿐 절대 사용해서는 안된다.
로 타입을 쓰면 제네릭이 안겨주는 안전성과 표현력을 모두 잃게 되기 때문이다.
List 같은 로 타입은 안되지만, List<Object>와 같은 매개변수화 타입은 괜찮다.
매개변수로 List를 받는 메소드에 List<String>을 넘길 수 있지만, List<Object> 를 받는 메소드에는 넘길 수 없다.
이는 제네릭의 하위 타입 규칙 때문으로 List<String> 은 List의 하위 타입이지만, List<Object> 의 하위 타입은 아니기 때문이다. (=불공변)
그 결과 List<Object> 같은 매개변수화 타입을 사용할 때와 달리 List 같은 로 타입을 사용하면 타입 안전성을 잃게 된다. (예를 들어, 로 타입 매개변수인 List 를 이용해 List<String> 을 받을 경우, List 에는 String 뿐만 아니라 다른 타입의 데이터도 넣을 수 있게 된다. 따라서 제네릭에서 보장하는 타입 안전성을 잃게 된다.)
예제 1 - 로 타입 매개변수를 이용해 제네릭에서 보장하는 타입 안전성을 잃음
// 런타임에 실패한다. (unsafeAdd 메소드가 로 타입을 사용)publicstaticvoidmain(String[] args) {
List<String> strings = newArrayList<>();
unsafeAdd(strings, Integer.valueOf(42));
Strings = strings.get(0); // 컴파일러가 자동 형변환 코드를 넣어준다.
}
// 매개변수로 로 타입을 받음privatestaticvoidunsafeAdd(Listlist, Objecto) {
list.add(o);
}
이 코드는 컴파일은 되지만 로 타입인 List를 사용하여 다음과 같은 경고가 발생한다.
Test.java:10: warning: [unchecked] unchecked call to add(E) as a member of the raw type List
list.add(o);
^
이 프로그램을 그대로 실행하면 strings.get(0)의 결과를 형변환하려 할 때 ClassCastException을 던진다. (Integer를 String으로 변환하려 시도하였기 때문이다.)
다음은 로 타입인 List를 매개변수화 타입인 List<Object>로 바꾼 다음에 다시 컴파일 해보자. 이번에는 다음 오류 메시지가 출력되며 컴파일조차 되지 않는다.
Test.java:5: error: incompatible types: List<String> cannot be converted to List<Object>
unsafeAdd(strings, Integer.valueOf(42));
^
결론은 로 타입을 사용하지말고 List<Object> 와 같은 매개변수화 타입이라도 이용해서 컴파일 타임에 타입 안전성을 지킬 수 있도록 하는 것이 좋다.
예제 2 - 로 타입 매개변수를 이용해 제네릭에서 보장하는 타입 안전성을 잃음
예제 1과 마찬가지로 동작은 하지만 로 타입을 사용해 안전하지 않다.
staticintnumElementsInCommon(Sets1, Sets2) {
intresult = 0;
for (Objecto1 : s1)
if (s2.contains(o1))
result++;
returnresult;
}
만약 원소의 타입을 몰라도 되는 로 타입이 쓰고 싶은 것이라면 비한정적 와일드 타입(unbounded wildcard type) 을 대신 사용하는 게 좋다.