item 29) 이왕이면 제네릭 타입으로 만들라

제네릭 타입 만들기

  • 클라이언트에서 직접 형변환해야 하는 Object 타입보다는 제네릭 타입이 더 안전하고 편리하다.

  • 클래스 선언에 타입 매개변수를 추가한다 (보통 타입 이름으로 E를 사용한다, item68)

  • Object 기반의 코드가 있다면, 적절한 타입 매개변수로 바꾼다.

public class Stack<E> {
    private E[] elements;
    private int size = 0;
    private static final int DEFAULT_INITIAL_CAPACITY = 16;

    public 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;
    }
    ... // isEmpty와 ensureCapacity 메서드는 그대로다.
}
  • E와 같은 실체화 불가 타입으론 배열을 만들 수 없어 new E[DEFAULT_INITIAL_CAPACITY]; 가 실패한다.

해결방법

  • 방법 1) 제네릭 배열 생성 금지 제약을 우회하기

    • Object 배열 생성한 후 형변환을 한다. 대신 안전성이 보장되는지 직접 확인해야 한다.

    • 비검사 형변환의 안전함이 증명되었다면 @SuppressWarnings 어노테이션으로 경고를 숨긴다.

    @SuppressWarnings("unchecked")
    public Stack() {
        elements = (E[]) new Object[DEFAULT_INITIAL_CAPACITY];
    }
  • 방법 2) elements 필드의 타입을 Object 배열으로 변경

    • 배열에 입력하는 부분에서 E 타입만 허용한다면, 형변환이 안전하다.

    public Stack() {
        @SuppressWarnings("unchecked") E result = (E) elements[--size];
    }

배열보다 리스트를 우선하라면서(item28) 왜 여기서는 배열을 쓰는가?

  • 제네릭 타입 안에서 리스트를 사용하는 게 항상 가능하지도, 꼭 더 좋은 것도 아니다.

  • 자바가 리스트를 기본 타입으로 제공하지 않아 ArrayList 같은 제네릭 타입도 결국은 기본 타입인 배열을 사용해 구현해야 한다.

  • HashMap 같은 제네릭 타입은 성능을 높일 목적으로 배열을 사용하기도 한다.

Last updated