아이템 28 : 배열보다는 리스트를 사용하라
배열과 제네릭 타입에는 중요한 차이가 두 가지 있다.
첫 번째, 배열은 공변이다. 어려워 보이는 단어지만 뜻은 간단하다. Sub가 Super의 하위 타입이라면 배열 Sub[]는 배열 Super[]의 하위 타입이 된다. 반면, 제네릭은 불공변이다. 즉, 서로 다른 타입 Type1과 Type2가 있을 때, List<Type1>은 List<Type2>의 하위 타입도 아니고 상위 타입도 아니다.
두 번째, 배열은 실체화된다. 배열은 런타임에도 자신이 담기로 한 원소의 타입을 인지하고 확인한다. 반면, 제네릭은 타입 정보가 런타임에는 소거된다. 원소 타입을 컴파일타임에만 검사하며 런타임에는 알수조차 없다는 뜻이다. 소거는 제네릭이 지원되기 전의 레거시 코드와 제네릭 타입을 함께 사용할 수 있게 해주는 메커니즘으로, 자바 5가 제네릭으로 순조롭게 전환될 수 있도록 해줬다.
이상의 주요 차이로 인해 배열과 제네릭은 잘 어우러지지 못한다. 예컨대 배열은 제네릭 타입, 매개변수화 타입, 타입 매개변수로 사용할 수 없다.
제네릭 배열을 만들지 못하게 막은 이유는 타입 안전하지 않기 때문이다. 이를 허용한다면 컴파일러가 자동 생성한 형변환 코드에서 런타임에 ClassCastException이 발생할 수 있다. 런타임에 ClassCastException이 발생하는 일을 막아주겠다는 제네릭 타입 시스템의 취지에 어긋나는 것이다.
비검사 형변환 경고를 제거하려면 배열 대신 리스트를 쓰면 된다.
핵심 정리
배열과 제네릭에는 매우 다른 타입 규칙이 적용된다. 배열은 공변이고 실체화되는 반면, 제네릭은 불공변이고 타입 정보가 소거된다. 그 결과 배열은 런타임에는 타입 안전하지만 컴파일타임에는 그렇지 않다. 제네릭은 반대다. 그래서 둘을 섞어 쓰기란 쉽지 않다. 둘을 섞어 쓰다가 컴파일 오류나 경고를 만나면, 가장 먼저 배열을 리스트로 대체하는 방법을 적용해보자.
'언어 > JAVA' 카테고리의 다른 글
[Effective Java] 이왕이면 제네릭 메서드로 만들라 (0) | 2020.03.23 |
---|---|
[Effective Java] 이왕이면 제네릭 타입으로 만들라 (0) | 2020.03.23 |
[Effective Java] 비검사 경고를 제거하라 (0) | 2020.03.22 |
[Effective Java] 로 타입은 사용하지 말라 (0) | 2020.03.21 |
[Effective Java] 톱레벨 클래스는 한 파일에 하나만 담으라 (0) | 2020.03.21 |