배열은 공변이고 제네릭은 불공변이다.
Object[] objectArray = new Long[1];
objectArray[0] = "string"; //ArrayStoreException
List<Object> ol = new ArrayList<Long>(); //호환되지 않는 타입 -> 컴파일 안됨
ol.add("string");
배열은 실체화되지만 제네릭은 타입 정보가 런타임 시에 소거된다.
→ 배열과 제네릭은 잘 어울리지 못함
[제네릭] Java에서 배열을 공변(covariant)으로 만든 이유는 무엇인가?
배열은 제네릭 타입, 매개변수화 타입, 타입 매개변수로 사용할 수없다.
new List<E>[], new List<String>[], new E[]와 같이 작성 → 컴파일 시 제네릭 배열 생성 오류
제네릭 배열을 허용한다면 컴파일러가 자동 생성한 형변환 코드에서 런타임에 ClassCastException이 발생할 수 있어 타입 안전성이 사라질 수 있음
→ 런타임에 ClassCastException 발생을 막아주겠다는 제네릭 타입 시스템 취지에 어긋남
제네릭 배열을 만들 수 있다면 생기는 문제는 다음과 같다.
List<String>[] stringLists = new List<String>[1]; //런타임 시 List[] 타입이 됨
List<Integer> intList = List.of(42); //런타임 시 List[] 타입이 됨
Object[] objects = stringLists; //배열은 공변이라 넣을 수 있음
objects[0] = intList; //제네릭은 소거 방식 구현이라 넣을 수 있음
String s = stringLists[0].get(0); //컴파일러가 꺼낸 원소를 String으로 형변환
//이때 ClassCastException 발생함