public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
pulic 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 = elements[--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);
}
}
-
클래스 선언에 타입 매개 변수를 추가한다.
- 타입 매개 변수의 이름은 보통
E
를 사용한다.
public class Stack<E> { private E[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; pulic Stack() { elements = new E[DEFAULT_INITIAL_CAPACITY]; } public void push(E e){ ensureCapacity(); elements[size++] = e; } public E pop() { if (size == 0) throw new EmptyStackException(); E result = elements[--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); } }
E
는 실체화 불가 타입이기 때문에 배열을 만들 수 없다.- 해결책 1) 제네릭 배열 생성 금지 제약 우회
Object
배열을 생성한 후 제네릭 배열로 형변환- 컴파일러 오류가 발생하진 않지만 경고가 발생하고, 일반적으로 안전하지 않다.
- 비검사 형변환이 안전함을 증명했다면 최소 범위에서
@Suppress Warning
어노테이션으로 해당 경고를 숨기자. - 명시적으로 형변환하지 않아도
ClassCasatException
걱정 없이 사용할 수 있게 된다. - 코드가 짧고, 가독성이 좋다는 장점을 가지고 있지만, 배열의 런타임 타입과 컴파일타임 타입이 다르기 때문에 힘 오염을 일으킬 수 있다.
- 해결책 2)
elements
필드의 타입을E[]
가 아닌Object[]
로 사용E
가 실체화 불가 타입이기 떄문에 런타임에 이루어지는 형변환이 안전한지 증명할 수 없다. (경고 발생)- 안전함을 증명하고, 경고를 숨기자.
- 해결책 1) 제네릭 배열 생성 금지 제약 우회
- 타입 매개 변수의 이름은 보통
- 새로운 타입을 설계할 때는 형변환 없이도 사용할 수 있도록 제네릭 타입을 사용하자!