아이템 26. 가능하면 제네릭 자료형으로 만들것
26. 가능하면 제네릭 자료형으로 만들것
public class Stack<E>{
private static final int DEFAULT_INITIAL_CAPACITY = 16;
private E[] elements;
private int size = 0;
public Stack(){
elements = new E[DEFAULT_INITIAL_CAPACITY];
}
public void push(E e){
ensureCpapcity();
elements[size++] = e;
}
public E pop(){
if(isEmpty())
throw new EmptyStackException();
E result = elements[--size];
elements[size] = null; // 기존 참조 제거
return result;
}
public boolean isEmpty() {
return 0 == size;
}
// Stack의 사이즈가 부족해 지면, 원래 크기(size)의 두배로 늘려줌
private void ensureCapacity(){
if(elements.length == size)
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}
위 클래스의 아래와 같은 오류가 발생한다.
Stack.java:8: generic array creation
elements = new E[DEFAULT_INITIAL_CAPCITY];
^
E
는 실체화 불가능 자료형으로 배열을 생성 할 수 없다.
해결 방법은 두 가지가 있다.
- 제네릭 배열을 만들수 없다는 조건을 우회 하는 것
배열 객체를 생성할 때, new Object
를 통해 배열을 만들어서 제네릭 배열형으로 형변환 시키는 방법으로
관리되는 모든 타입이 E
로 보장될 될때 사용 가능하다.
// elements 배열에는 push(E)를 통해 전달된 E 형의 객체만 저장된다.
// 이 정도면 형 안정성은 보장할 수 있지만, 배열의 실행시간 자료형은 E[]가
// 아니라 항상 Object[] 이다.
@SuppressWarnings("unchecked")
public Stack() {
elements = (E[]) new Object[DEFAULT_INITIAL_CAPACITY];
}
- 배열의 자료형을
E[]
에서Object[]
로 바꾸는 것
private Object[] elements;
...
public Stack() {
elements = (E[]) new Object[DEFAULT_INITIAL_CAPACITY];
}
...
// 무점검 경고를 적절히 억제한 사례
public E pop() {
if (size = 0)
throw new EmptyStackException();
// 자료형이 E인 원소만 push하므로, 아래의 형변환은 안전하다.
@SuppressWarnings("unchecked")
E result = elements[--size];
elements[size] = null; // 기존 참조 제거
return result;
}
제네릭 배열 해결책 정리
-
무점검 형변환(unchecked cast) 경고 억제의 위험성은 스칼라(scala) 자료형 보다 배열 자료형이 더 크기 때문에, 두번째 해법이 더 낫다고 볼 수 있다.
-
현실적으로
E
배열을 사용하는 코드가 이곳 저것에 흩어져 있다면, 배열 생성 시 첫번째 방법으로는E[]
으로 한번만 형변환을 하면되지만, 두번째 방법으로는 코드 여기저기에서 E로 형변환을 해야하므로 첫번째 방법이 더 낫다