제네릭 타입은 배열생성이 안될까?

서버란·2024년 8월 31일

자바 궁금증

목록 보기
9/35
  • 자바에서 제네릭 타입으로 배열을 생성할 수 없는 이유는 타입 안전성과 런타임 시의 타입 정보 손실(type erasure) 때문입니다. 자세히 설명하자면 다음과 같습니다.

1. 타입 소거 (Type Erasure)

  • 자바에서 제네릭은 컴파일 타임에만 존재하며, 컴파일 후에는 제네릭 타입 정보가 제거됩니다. 이 과정을 타입 소거(type erasure)라고 합니다. 제네릭 타입 T는 컴파일 후에는 실제 타입 정보를 갖지 않게 되며, Object로 변환되거나, 특정한 바운드(제한된 타입)가 있는 경우에는 그 바운드 타입으로 변환됩니다.

예를 들어, 다음과 같은 제네릭 클래스가 있다고 가정해봅시다.

class Box<T> {
    private T value;
    public void setValue(T value) { this.value = value; }
    public T getValue() { return value; }
}
  • 컴파일된 후에는 Box에서 T는 제거되고 Object로 변환됩니다.

2. 타입 안전성 문제

  • 제네릭 타입으로 배열을 생성할 수 없는 이유 중 하나는 타입 안전성을 보장할 수 없기 때문입니다. 자바에서는 배열이 그 타입을 런타임에 추적합니다. 하지만 제네릭 타입은 컴파일 타임에만 유효하고, 런타임 시에는 타입이 소거되기 때문에 배열과 제네릭을 함께 사용할 경우 타입 안전성을 보장하기 어렵습니다.

예를 들어, 제네릭 타입으로 배열을 생성하는 코드가 있다고 가정해봅시다.

Box<String>[] boxes = new Box<String>[10]; // 컴파일 오류
  • 이 코드가 허용된다면, 다음과 같은 상황이 발생할 수 있습니다:
Object[] objArray = boxes; // 제네릭 배열을 Object 배열로 캐스팅
objArray[0] = new Box<Integer>(); // 다른 타입의 Box를 넣음
String value = boxes[0].getValue(); // 런타임에서 타입 불일치 오류 발생 가능
  • 위 코드에서 boxes 배열은 Box 배열로 선언되었지만, 배열의 타입 정보는 런타임에 추적되므로, Box 객체를 배열에 할당해도 컴파일러는 이를 감지할 수 없습니다. 결과적으로 런타임에 타입 불일치로 인한 예외가 발생할 수 있습니다.

3. 제네릭과 배열의 관계

  • 배열은 런타임에 자신의 타입을 알고 있어야 합니다. 하지만 제네릭 타입은 컴파일 타임에만 존재하기 때문에, 배열의 런타임 타입을 결정할 수 없고, 이로 인해 타입 안전성을 보장할 수 없게 됩니다.

우회 방법

  • 제네릭 배열을 직접 생성할 수는 없지만, 몇 가지 우회 방법이 존재합니다.

  • Object 배열을 생성한 후 캐스팅하기:

@SuppressWarnings("unchecked")
Box<String>[] boxes = (Box<String>[]) new Box[10];
  • 이 방법은 경고를 억제하고, 제네릭 배열을 사용할 수 있게 합니다. 그러나 여전히 타입 안전성을 보장하지 못하므로 조심해야 합니다.

  • 리스트를 사용하기:
    자바 컬렉션 프레임워크의 리스트를 사용하는 것이 더 안전한 방법입니다.

List<Box<String>> boxList = new ArrayList<>();
  • 리스트를 사용하면 제네릭의 장점을 그대로 유지하면서 타입 안전성을 보장할 수 있습니다.

결론

제네릭 타입으로 배열을 생성할 수 없는 이유는 타입 소거로 인해 제네릭 타입의 런타임 타입 정보를 보존할 수 없고, 이로 인해 타입 안전성이 보장되지 않기 때문입니다. 이러한 이유로 자바에서는 제네릭 타입으로 배열을 직접 생성하는 것을 허용하지 않습니다.

profile
백엔드에서 서버엔지니어가 된 사람

0개의 댓글