Object 기반 스택 - 제네릭이 필요하다
public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {
elements = new Object[DEFAULT_INITIAL_CAPACITY];
}
public void push(Object e) {
ensureCapacity();
elements[size++] = e;
}
public Object pop() {
if (size == 0
throw new EmptyStackException();
Object result = elemtns[--size];
elements[size] = null; // 다 쓴 참조 해제
return result;
}
public boolean isEmpty() {
return size == 0;
}
private void ensureCapacity() {
if (elements.length == size)
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}
이 클래스에는 제네릭 타입이어야 한다. 지금은 클라이언트가 스택에서 꺼낸 객체를 형변환 해야하는데, 이때 런타임 오류가 날 위험이 있다.
클래스 선언에 타입 매개변수를 추가하면된다.
제네릭 스택 첫 단계 - 컴파일되지 않는다
public class Stack {
private E[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {
elements = new Object[DEFAULT_INITIAL_CAPACITY];
}
public void push(E e) {
ensureCapacity();
elements[size++] = e;
}
public E pop() {
if (size == 0)
throw new EmptyStackException();
E result = elemtns[--size];
elements[size] = null; // 다 쓴 참조 해제
return result;
}
...
}
아이템 28에 나오는 것처럼 E와 같은 실체화 불가 타입으로 배열 생성 안된다.
방법은 두 가지다.
@SuppressWarnings("unchecked")
public Stack() {
elements = (E[]) new Object[DEFAULT_INITIAL_CAPACITY];
}
배열 elements가 private 필드에 저장되고 클라이언트에 반환되거나 다른 메서드에 전달되지 않아서 완전하긴하다.
가독성이 더 좋다. 배열의 타입을 E[]
로 선언하며 E 타입 인스턴스만 받읆을 어필한다. 형변환을 배열 생성시에만 해주면 된다. 하지만 (E가 Object)가 아닌한 배열의 런타임 타입이 컴파일타임 타입과 달라 힙 오염을 일으킨다.
E[]
에서 Object[]
로 변경E는 실체화 불가 타입이므로 컴파일러는 런타임에 이뤄지는 형변환이 안전한지 증명할 방법이 없다.
//이 배열의 런타임 타입은 E[]가 아닌 Object[]다
public E pop() {
if (size == 0)
throw new EmptyStackException();
@SuppressWarnings("unchecked")
E result = (E) elements[--size];
elements[size] = null; // 다 쓴 참조 해제
return result;
}
컴파일러가 런타임에 이뤄지는 형변환이 안전한지 알 수없다.
그런데 지금까지 설명은 아이템 28. 배열보다는 리스트를 사용하라과 모순되어보인다.
제네릭 타입 안에서 리스트를 사용하는게 항상 가능하지도 않고, ArrayList
도 결국 내부적으로 기본 타입 배열을 쓴다. HashMap
도 성능을 높일 목적으로 배열을 쓴다.
결론: 기존 타입 중 제네릭이었어야 하는게 있다면 제네릭 타입으로 변경하자. 기존 클라이언트에는 아무 영향을 주지 않으면서, 새로운 사용자를 편하게 해준다.