자바에서 제네릭 배열을 어떻게 생성하나요?

조회수 9948회

자바 제네릭 구현 때문에, 아래와 같이 구현할 수가 없습니다:

public class GenSet<E> {
    private E a[];

    public GenSet() {
        a = new E[INITIAL_ARRAY_LENGTH]; // error: generic array creation
    }
}

타입의 안전성을 유지하면서 어떻게 구현할 수 있을까요?

이전에 자바 포럼에서 다음과 같은 해결책을 찾아보았습니다.

import java.lang.reflect.Array;

class Stack<T> {
    public Stack(Class<T> clazz, int capacity) {
        array = (T[])Array.newInstance(clazz, capacity);
    }

    private final T[] array;
}

그런데 위의 소스코드가 어떻게 동작하는지 잘 이해가 되지 않습니다. 도와주세요.

1 답변

  • 좋아요

    3

    싫어요
    채택 취소하기

    질문에 대한 답을 차례로 설명하겠습니다.

    클래스 GenSet은 "checked"인가요? "unchecked"인가요? 그것의 의미를 아시나요?

    • Checked: strong typing을 의미합니다. strong typing이란 서로 다른 데이터 유형의 객체 간의 상호 작용을 제한하는 것이지요. 한마디로 강력하게 타입 체크를 한다고 이해하셔도 되겠지요. GenSet을 checked로 정의하면, GenSetClass<E>를 입력으로 받는 생성자를 정의하여 객체들의 타입이 무엇인지를 명확히 알 수 있어서 만약 타입이 E가 아닌 객체가 메소드의 입력으로 전달되면 메소드들은 익셉션을 발생하게 됩니다. Collections.checkedCollection을 참고하세요.

    이와 같은 경우로 정의하면, 다음과 같은 코드로 구현할 수 있겠지요:

    public class GenSet<E> {
    
        private E[] a;
    
        public GenSet(Class<E> c, int s) {
            // Use Array native method to create array
            // of a type only known at run time
            @SuppressWarnings("unchecked")
            final E[] a = (E[]) Array.newInstance(c, s);
            this.a = a;
        }
    
        E get(int i) {
            return a[i];
        }
    }
    
    • Unchecked: weak typing을 의미합니다. 즉, 타입 체크가 약하다는 것이겠지요. 그래서 메소드의 입력으로 객체를 전달할 때 그 객체의 타입을 체크하지 않습니다.

    이와 같은 경우로 정의하면, 다음과 같은 코드로 구현할 수 있습니다.

    public class GenSet<E> {
    
        private Object[] a;
    
        public GenSet(int s) {
            a = new Object[s];
        }
    
        E get(int i) {
            @SuppressWarnings("unchecked")
            final E e = (E) a[i];
            return e;
        }
    }
    

    배열의 변수타입은 타입 파라미터에 대하여 타입 소거 (type erasure)되어야 한다는 점을 주의해야 합니다. 타입 소거는 소스코드에 있는 타입 정보는 런타임시에는 불필요하기 때문에 컴파일시 제거된다는 것입니다.

    public class GenSet<E extends Foo> { // E has an upper bound of Foo
    
        private Foo[] a; // E erases to Foo, so use Foo[]
    
        public GenSet(int s) {
            a = new Foo[s];
        }
    
        ...
    }
    

    이것이 자바 제네릭의 약점입니다. "제네릭" 클래스는 실행시 정해지는 구체화된 타입이 무엇인지 알지 못하기 때문에, 타입 소거로 구현하여야 합니다. 그러므로 타입 체크와 같은 몇몇 명확한 메커니즘이 구현되지 않으면 타입의 안전성을 보장할 수가 없겠지요.

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)