-
Notifications
You must be signed in to change notification settings - Fork 1
item 26 leekyunghee
leekyunghee edited this page Jul 31, 2020
·
7 revisions
List 인터페이스는 원소의 타입을 나타내는 타입 매개변수 E를 받는다. 인터페이스의 완전한 이름은 List지만 짧게 그냥 List 라고도 자주쓴다.
- 제네릭 타입은 일련의 매개변수화 타입을 정의한다. (클래스/인터페이스 이름 + <타입>)
- Raw type이란 List의 Raw 타입은 List다.
- Raw type은 타입 선언에서 제네릭 타입 정보가 전부 지워진 것처럼 동작하는데 제네릭이 도래하기 전 코드와 호환되도록 하기 위한 궁여지책이라 할 수 있다.
- Raw type도 함께 정의된다.
[before] 컬렉션의 Raw 타입 - 따라하지 말 것!
private final Collection stamps = ...;
// 이 코드를 사용하면 실수로 도장(Stamp) 대신 동전(Coin)을 넣어도 아무 오류 없이 컴파일되고 실행된다.(컴파일러가 모호한 경고 메시지를 보여주긴 할 것이다.)
stamps.add(new Coin(...)); // "unchecked call" 경고를 내뱉는다.
컬렉션에서 이 동전을 다시 꺼내기 전에는 오류를 알아채지 못한다.
[before] 반복자의 로 타입 - 따라하지 말 것!
for (Iterator i = stamps.iterator(); i.hasNext();) {
Stamp stamp = (Stamp) i.next(); // ClassCastException 을 던진다.
stamp.cancel();
}
[after] 매개변수화된 컬렉션 타입 - 타입 안전성 확보
private final Collection<Stamp> stamps = ...;
// 컴파일러가 인지하게 됨
// 컴파일러는 컬렉션에서 원소를 꺼내는 모든 곳에 보이지 않는 형변환을 추가하여 절대 실패하지 않음을 보장한다.
Test.java:9: error: incompatible types: Coin cannot be converted to Stamp
stamp.add(new Coin());
// Stamp용 컬렉션에 Coin을 넣는다는 예시
// 예를 들어 BigDecimal용 컬렉션에 BigInteger를 넣는 실수는 그리 억지 같지 않을 것
// 로타입(타입 매개변수가 없는 제네릭 타입)을 쓰는 걸 언어 차원에서 막아 놓지는 않았지만 절대로 써서는 안된다.
// 로 타입을 쓰면 제네릭이 안겨주는 안전성과 표현력을 모두 잃게 된다.
- Raw 타입인 List와 매개변수화 타입은 List의 차이
List는 제네릭 타입에서 완전히 발을 뺀 것이고 List는 모든 타입을 허용한다는 의사를 컴파일러에 명확히 전달
매개변수로 List를 받는 메서드에 List을 넘길 수 있지만 List를 받는 메서드에는 넘길 수 없다.
List은 Raw 타입인 List의 하위 타입이지만 List의 하위 타입은 아니다.
// 코드 26-4 런타임에 실패한다. - unsafeAdd 메서드가 Raw 타입(List)을 사용
public class Raw {
public static void main(String[] args) {
List<String> strings = new ArrayList<>();
unsafeAdd(strings, Integer.valueOf(42));
String s = strings.get(0); // 컴파일러가 자동으로 형변환 코드를 넣어준다.
}
private static void unsafeAdd(List list, Object o) {
list.add(o); // [unchecked] call to add(E) as member of the raw type List
}
}
핵심 정리
Raw 타입을 사용하면 런타임에 예외가 일어날 수 있으니 사용하면 안된다.
Set<Object>와 Set<?>은 안전하지만 로 타입인 Set은 안전하지 않다.