배열보다는 리스트를 사용하라

배열과 제네릭 타입의 차이

배열은 공변, 제네릭은 불공변

배열은 Sub가 Super의 하위 타입이라면 Sub[]는 Super[]의 하위 타입이 된다.

Object[] arr = new Long[1];
arr[0] = "타입이 달라 넣을 수 없다."; // 런타임에 실패

제네릭은 서로 다른 타입 Type1과 Type2가 있을 때, List<Type1>List<Type2>의 하위 타입도 아니고 상위 타입도 아니다.

List<Object> list = new ArrayList<Long>(); // 호환되지 않는 타입이라 컴파일타임에 실패
list.add("타입이 달라 넣을 수 없다.");

배열은 실체화되지만 제네릭은 타입정보가 소거

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

제네릭은 타입정보가 런타임에는 소거된다. 원소 타입을 컴파일타임에만 검사하며 런타임에는 알 수조차 없다. 소거는 제네릭이 지원되기 전의 레거시 코드와 제네릭 타입을 함께 사용할 수 있게 해주는 매커니즘으로, 자바5가 제네릭으로 순조롭게 전환될 수 있도록 해줬다.

제네릭 배열을 만들지 못하게 막은 이유

배열은 타입 안전하지 않기 때문에 제네릭 타입, 매개변수화 타입, 타입 매개변수로 사용할 수 없다. 이를 허용한다면 컴파일러가 자동 생성한 형변환 코드에서 런타임에 ClassCastException이 발생할 수 있다. 런타임에 ClassCastException이 발생하는 일을 막아주겠다는 제네릭 타입 시스템의 취지에 어긋난다.

실체화 불가 타입

E, List<E>, List<String> 같은 타입을 실체화 불가 타입이라 한다. 실체화되지 않아서 런타임에는 컴파일타임보다 타입 정보를 적게 가지는 타입이다. 매개변수화 타입 가운데 실체화될 수 있는 타입은 List<?>, Map<?, ?> 같은 비한정적 와일드카드 타입뿐이다. 배열을 비한정적 와일드카드 타입으로 만들 수는 있지만, 유용하게 쓰일 일은 없다.

배열을 리스트로 변환

public class Chooser {
    private final Object[] choiceArray;

    public Chooser(Collection choices) {
        choiceArray = choices.toArray();
    }

    public Object choose() {
        Random rnd = ThreadLocalRandom.current();
        return choiceArray[rnd.nextInt(choiceArray.length)];
    }
}

위 클래스를 사용하려면 choose 메서드를 호출할 때마다 반환된 Object를 원하는 타입으로 형변환해야 한다. 혹시나 타입이 다른 원소가 들어 있었다면 런타임에 형변환 오류가 난다.

public class Chooser<T> {
    private final List<T> choiceList;

    public Chooser(Collection<T> choices) {
        choiceList = new ArrayList<>(choices);
    }

    public T choose() {
        Random rnd = ThreadLocalRandom.current();
        return choiceList.get(rnd.nextInt(choiceList.size()));
    }
}

배열로 형변환할 때 제네릭 배열 생성 오류나 비검사 형변환 경고가 뜨는 경우 대부분은 배열 E[] 대신 컬렉션인 List<E>를 사용하면 해결된다. 코드가 조금 복잡해지고 성능이 살짝 나빠질 수도 있지만, 타입 안정성과 상호운용성은 좋아진다.

배열과 제네릭에는 매우 다른 타입 규칙이 적용된다. 배열은 공변이고 실체화되는 반면, 제네릭은 불공변이고 타입 정보가 소거된다. 둘을 섞어 쓰다가 컴파일 오류나 경고를 만나면, 가장 먼저 배열을 리스트로 대체하는 방법을 적용하자.

Comments