[Effective Java]Item28. 배열보다는 리스트를 사용하라

최강일·2024년 7월 13일
0

Effective Java

목록 보기
12/17

배열 vs 제네릭 차이

공변성 : 부모 타입과 자식 타입 사이의 관계가 그대로 유지되는 성질
불공변성 : 타입 간의 상속 관계가 유지되지 않는 성질

1. 첫번째 차이

배열은 공변인다.sub[]가 super[]의 하위 타입이라면 함께 변한다.
반대로 제네릭은 불공변이다. 즉, List<"type1">,List<"type2">는 상위도 아니고 하위도 아니다.

이것만 보면 제네릭에 문제가 있다고 생각할 수도 있지만, 사실 문제는 배열에 있다.

ex)

//런타임에 실패한다.
Object[] objectArr = new Long[1];
objectArr[0] = "string"; //ArrayStoreException

//컴파일 실패
List<Object> ol = new ArrayList<Long>();
ol.add("string");

어느쪽이든 Long 타입에 String을 넣을 수 없다.
다만 배열에서는 런타임에야 알게 되지만, 리스트를 사용하면 컴파일할 때 바로 알 수 있다.

2. 두번째 차이

배열은 실체화된다.

배열은 런타임에도 자신이 담기로 한 원소의 타입을 인지하고 확인한다.
그래서 위 예제에서 Long배열에 String을 넣으려고하면 ArrayStoreException이 발생한다.

반면, 제네릭은 타입 정보가 런타임에는 소거된다.
원소 타입을 컴파일시에만 검사하며 런타임에는 알수조차 없다는 뜻이다.

때문에 배열과 제네릭은 어울리지 못한다.
배열은 제네릭 타입, 매개변수화 타입, 타입 매개변수로 사용할 수 없다.
즉, new List[], new List[], new E[]로 사용하면 컴파일할 때 제네릭 배열 생성 오류를 일으킨다.

핵심 정리

배열은 공변이고 실체화되는 반면, 제네릭은 불공변이고 타입 정보가 소거된다.

결과적으로, 배열은 런타임에는 타입 안전하지만 컴파일 타임에는 그렇지 않다.
제네릭은 런타임에는 타입 안전하지 않고 컴파일 타임에는 안전하다.

따라서, 배열과 제네릭을 섞어쓰는 것은 쉽지 않다.
만약 둘을 섞어 쓰다가 컴파일 오류나 경고를 만나면, 가장 먼저 배열을 리스트로 대체하는 방법을 적용해보도록 한다.

profile
Search & Backend Engineer

0개의 댓글