제네릭
[아이템 28. 배열보다는 리스트를 사용하라]
[핵심 정리]
- 배열은 실체화, 공변 등의 문제가 있다.
- 위의 문제를 제네릭의 리스트는 완벽하게 해결해준다. 그러니까 해당 문제가 발생하면 우리는 뒤도 돌아보지 말고 제네릭 리스트를 이용해 배열을 교체해주자
[배열과 리스트의 차이]
1. 공변
- sub가 super의 하위 타입이라면 배열 sub[]는 배열 super[]의 하위 타입이다.
- 그러나 제네릭(리스트 등)은 하위 타입도, 상위 타입도 아니다.
1-1. 런타임시 오류를 발견하는 배열
Object[] o = new Long[1];
o[0] = "String 값을 야무지게 넣어야지~";
List<Object> genericList = new List<Long>();
genericList.add("타입이 달라서 넣을 수 없삼");
- 위의 코드는 모두 다 허용하지 않는 문법이다. 그러나 배열의 경우엔 런타임시에 이 문제가 드러나고 제네릭의 경우엔 컴파일 시 해당 문제를 발견한다.
- 가능한 컴파일시에 오류를 잡아내는 것이 좋다.
2. 배열의 실체화
- 배열이 실체화 된다는 의미는 런타임에도 자신이 담기로 한 원소의 타입을 인지하고 확인한다. 그래서 Long 타입의 배열에 String 값을 넣으려 하면 ArrayStoreException이 발생하게 된다.
- 런타임시까지도 담아둔 원소의 데이터 타입을 인지하고 있는 배열과 달리, 제네릭의 경우엔 런타임시에는 타입이 소거되기 때문에 instanceof를 사용할 땐 로타입을 쓰는 것을 권장했다.
- 타입의 소거는 제네릭 지원 전의 코드와 제네릭의 코드를 함께 사용할 수 있도록 해주는 매커니즘이다.
- 그래서 타입을 끝까지 가져가는 배열의 실체화는 제네릭과 잘 어울리지 못한다.
3. 제네릭 타입, 매개변수화 타입, 타입 매개변수로 사용할 수 없는 배열
- 배열은 제네릭 타입, 매개변수화 타입, 타입 매개변수로 사용할 수 없다.
- List<
E
>[] 제네릭 배열 불가
- new List<
String
>[]
- new E[]
4. 제네릭 배열을 막아둔 이유
- 타입이 안전하지 않기 때문이다.
- 컴파일 시 컴파일러가 제공하는 자동 형변환에서 런타임시 ClassCastException이 발생할 수 있기 때문이다.
[배열 대신 제네릭]
- 배열의 경우엔 형변환할 때 문제가 많다.
- 이를 제네릭을 사용해서 해결하면 좋다.
- 제네릭과 배열을 같이 합쳐 쓰다가 오류가 나면 가장 먼저 배열을 리스트로 대체하는 방법을 고려하자