안녕하세요 Dev JaeIn 입니다.
지난 포스팅에 이어 제네릭으로 스택을 만들어
일반 스택과 제네릭 스택을 비교해보는 포스팅을 진행하겠습니다.
그리고 비교를 통해 제네릭 스택이 어떠한 이점이 있는지 확인해보겠습니다.
public class NomalStack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_SIZE = 16;
public NomalStack() {
elements = new Object[DEFAULT_SIZE];
}
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;
}
public int size() {
return size;
}
/**
* 사이즈체크 후 배열 사이즈 증가
*/
private void ensureCapacity() {
if(elements.length == size)
elements = Arrays.copyOf(elements, 2*size+1);
}
}
위와 같이 소스가 구성되어 있습니다. 별 문제 없이 잘 동작합니다.
그런데 문제점이 존재합니다. Object로 이루어져 있어서 어떤 타입이 들어와도 동작이 잘 되는건 확실합니다.
하지만, 여러 타입이 중복되어 들어갔을 경우 어떤 현상이 발생하는지 보도록 하죠.
public class Main {
public static void main(String[] args) {
//해당 스택은 String 타입의 스택입니다.
NomalStack st = new NomalStack();
st.push("abcd");
st.push(1234);
String[] ary = new String[st.size()];
//ClassCastException 발생.
for(int i = 0 ; i < ary.length ; i++) {
ary[i] = (String) st.pop();
}
}
}

위 사진과 같이 컴파일은 진행되고 런타임시에 발생하는것을 확인 할 수 있습니다.
제네릭을 사용해서 크게 달라지는 부분은 없습니다. 다만, 클래스 선언부에 타입 매개변수만 추가해주고 리턴 타입이 Object인 부분을 타입 매개변수로만 변경해주면 됩니다.
제네릭 타입으로 변경 후 소스입니다. 하지만 다음 사진과 같이 컴파일 에러가 발생합니다. 그 이유는 이전 포스팅에서 설명한것과 같이 제네릭은 type-safe 하지 않기 때문입니다. 그래서 다음 방법을 통해 우회하여 생성해보도록 하겠습니다.


배열의 멤버필드를 private로 선언하여 클라이언트로 반환되거나 다른 메서드에서 접근 불가능하도록 만들면 가능합니다.
또한 push 메소드에서 원소 타입은 항상 E 인스턴스만 담기 때문에 문제가 없습니다.
@SuppressWarnings(“unchecked”)를 추가해주고 윗부분에 상세하게 왜 해당 부분이 타입이 안전한지 주석으로 달아주면 됩니다.
다음은 완성된 코드입니다.
public class GenericStack<E> {
private E[] elements;
private int size = 0;
private static final int DEFAULT_SIZE = 16;
//push 메소드는 E 인스턴스만 담는다. 따라서 타입 안전성을 보장한다.
//해당 배열의 런타임 타입은 E[]가 아닌 Object[] 이다.
@SuppressWarnings("unchecked")
public GenericStack() {
elements = (E[])new Object[DEFAULT_SIZE];
}
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;
}
public int size() {
return size;
}
/**
* 사이즈를 늘려준다.
*/
private void ensureCapacity() {
if(elements.length == size)
elements = Arrays.copyOf(elements, 2*size+1);
}
}

여기까지 읽어주셔서 감사합니다!!