Item 29. Generic Type

이왕이면 μ œλ„€λ¦­ νƒ€μž…μœΌλ‘œ λ§Œλ“€λΌ

ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ 직접 ν˜•λ³€ν™˜ν•΄μ•Όν•˜λŠ” 것보단 ν˜•λ³€ν•œ 없이 μ‚¬μš©ν•  수 μžˆλ„λ‘ ν•˜λŠ” 것이 μ’‹λ‹€. μ΄λ ‡κ²Œ κ΅¬ν˜„ν•˜κΈ° μœ„ν•΄μ„  μ œλ„€λ¦­ νƒ€μž…μœΌλ‘œ λ§Œλ“€μ–΄μ•Ό ν•˜λŠ” κ²½μš°κ°€ 많기 λ•Œλ¬Έμ— μƒˆλ‘œμš΄ νƒ€μž…μ„ 섀계할 땐 μ œλ„€λ¦­ νƒ€μž…μ„ κ³ λ €ν•΄λ³΄λŠ” 것이 μ’‹λ‹€.

예제 μ½”λ“œ

μ œλ„€λ¦­ νƒ€μž… 적용 μ „ μ½”λ“œ

class Stack {
    private static final int DEFAULT_INITIAL_CAPACITY = 16;
    private Object[] elements;
    private int size = 0;

    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 = 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);
        }
    }
}

class Main {

    public static void main(String[] args) {
        Stack stack = new Stack();

        stack.push("Hello");
        stack.push("Ogu");

        while (!stack.isEmpty()) {
            System.out.println(stack.pop());
        }
    }
}

μœ„μ™€ 같은 Stack ν΄λž˜μŠ€κ°€ μžˆλŠ” 경우 μ œλ„€λ¦­μ„ μ μš©ν•˜λŠ” 것이 μ’‹λ‹€. μœ„μ²˜λŸΌ μ œλ„€λ¦­ μ½”λ“œλ₯Ό μ μš©ν•˜λ”λΌλ„ 기쑴에 μ‚¬μš©ν•˜λ˜ ν΄λΌμ΄μ–ΈνŠΈ μ½”λ“œλ„ λ³€κ²½ν•  ν•„μš”κ°€ μ—†λ‹€.(κ²½κ³ κ°€ λ°œμƒν•˜μ§€λ§Œ Raw Type으둜 μ‚¬μš©ν•  μˆ˜λŠ” μžˆμ–΄ μ—λŸ¬λŠ” λ°œμƒν•˜μ§€ μ•ŠμŒ)

μ œλ„€λ¦­ νƒ€μž… 적용 μ½”λ“œ

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

    public Stack() {
        elements = (E[]) new Object[DEFAULT_INITIAL_CAPACITY]; // κ²½κ³  λ°œμƒ, Unchecked cast: 'java.lang.Object[]' to 'E[]'
    }

    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);
        }
    }
}


class Main {

    public static void main(String[] args) {
        // κ²½κ³  λ°œμƒ, Raw use of parameterized class 'Stack'
        Stack stack = new Stack();

        stack.push("Hello");
        stack.push("Ogu");

        while (!stack.isEmpty()) {
            System.out.println(stack.pop());
        }
    }
}

ν΄λΌμ΄μ–ΈνŠΈ(Main) μ½”λ“œμ˜ 경고도 λ°œμƒν•˜μ§€λ§Œ, μƒμ„±μžμ—μ„œ λ°œμƒν•˜λŠ” 비검사 κ²½κ³ λ₯Ό μ œκ±°ν•˜κΈ° μœ„ν•΄ @SuppressWarnings("unchecked") μ–΄λ…Έν…Œμ΄μ…˜μ„ μΆ”κ°€ν•  수 μžˆλ‹€.

@SuppressWarnings("unchecked") μ–΄λ…Έν…Œμ΄μ…˜ μΆ”κ°€

μƒμ„±μžμ— @SuppressWarnings("unchecked") μ–΄λ…Έν…Œμ΄μ…˜ μΆ”κ°€ν•˜λŠ” 방법과 ν•„λ“œμ˜ elementsλ₯Ό Object λ°°μ—΄λ‘œ μ„ μ–Έν•˜λŠ” 방법이 μžˆλ‹€. 두 방법에 정닡이 μžˆλŠ” 것은 μ•„λ‹ˆλ©° μž₯/단점이 있기 λ•Œλ¬Έμ— 상황에 맞게 μ‚¬μš©ν•˜λ©΄ λœλ‹€.

  • μƒμ„±μžμ— @SuppressWarnings("unchecked") μ–΄λ…Έν…Œμ΄μ…˜ μΆ”κ°€

class Stack<E> {

    // ...

    // λ©”μ„œλ“œμ— 적용
    @SuppressWarnings("unchecked")
    public Stack() {
        elements = (E[]) new Object[DEFAULT_INITIAL_CAPACITY];
    }

    // ...
}

μ»΄νŒŒμΌλŸ¬μ—μ„  νƒ€μž… μ•ˆμ „ν•œμ§€ 증λͺ…ν•  수 μ—†μ§€λ§Œ, κ°œλ°œμžλŠ” νƒ€μž… μ•ˆμ „ν•˜λ‹€κ³  ν™•μ‹ ν•  수 μžˆμ„ λ•Œ μ‚¬μš©ν•˜λŠ” 방법이닀. μœ„ μ½”λ“œμ—μ„œλŠ” μ•„λž˜μ˜ 쑰건을 λ§Œμ‘±ν•˜κΈ° λ•Œλ¬Έμ— νƒ€μž… μ•ˆμ „ν•˜λ‹€κ³  ν™•μ‹ ν•  수 μžˆλ‹€.

  1. elementsκ°€ private ν•„λ“œμ— μ €μž₯됨: ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ 직접 μ ‘κ·Ό λΆˆκ°€

  2. ν΄λΌμ΄μ–ΈνŠΈλ‚˜ λ‹€λ₯Έ λ©”μ„œλ“œμ— μ „λ‹¬λ˜λŠ” 일이 μ—†μŒ: elements 배열을 λ°˜ν™˜ν•˜μ§€ μ•Šμ•„ ν΄λΌμ΄μ–ΈνŠΈκ°€ 데이터 ꡬ쑰에 μ ‘κ·Όν•  수 μ—†μŒ

  3. push λ©”μ„œλ“œμ—μ„œ elements 배열에 μ €μž₯λ˜λŠ” νƒ€μž…μ„ E둜 지정: elements 배열에 데이터λ₯Ό μΆ”κ°€ν•˜λŠ” μœ μΌν•œ λ©”μ„œλ“œμ΄λ©°, elements 배열에 μ €μž₯λ˜λŠ” μ›μ†Œμ˜ νƒ€μž…μ΄ E둜 ν•œμ •λ˜μ–΄ 있음

이 방법은 가독성이 더 μ’‹μœΌλ©°, elements λ°°μ—΄ 생성 μ‹œ ν•œ 번만 ν˜•λ³€ν™˜μ„ ν•˜κΈ° λ•Œλ¬Έμ— κ°„νŽΈν•˜λ‹€. ν•˜μ§€λ§Œ λ°°μ—΄μ˜ λŸ°νƒ€μž„ νƒ€μž…μ΄ μ»΄νŒŒμΌνƒ€μž„ νƒ€μž…κ³Ό 달라지기 λ•Œλ¬Έμ—(Generic Type Erasure) νž™ μ˜€μ—Όμ΄ λ°œμƒν•  수 μžˆλ‹€.(μœ„ μ½”λ“œμ—μ„  λ°œμƒν•˜μ§€ μ•ŠμŒ)

** νž™ μ˜€μ—Ό(Heap Pollution): JVM νž™ λ©”λͺ¨λ¦¬ μ˜μ—­μ— μ˜€μ—Όμ΄ 된 μƒνƒœ, μ œλ„€λ¦­μ—μ„œμ˜ νž™ μ˜€μ—Όμ€ 적용된 μ œλ„€λ¦­ νƒ€μž…κ³Ό λ‹€λ₯Έ νƒ€μž…μ˜ 객체λ₯Ό μ €μž₯ν•  λ•Œ λ°œμƒν•˜λŠ” 것을 의미

  • ν•„λ“œμ˜ elementsλ₯Ό Object λ°°μ—΄λ‘œ μ„ μ–Έ

class Stack<E> {
    private Object[] elements; // E -> Object λ³€κ²½
    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();
        }
        @SuppressWarnings("unchecked")      // νƒ€μž… μ•ˆμ „μ„±μ΄ 보μž₯λ˜μ§€ μ•ŠμŒμ„ μ•Œλ €μ£ΌκΈ° μœ„ν•΄ μΆ”κ°€
        E result = (E) elements[--size];    // Object 배열이기 λ•Œλ¬Έμ— ν˜•λ³€ν™˜ μΆ”κ°€
        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);
        }
    }
}

Object νƒ€μž…μœΌλ‘œ λ³€ν™˜ν–ˆκΈ° λ•Œλ¬Έμ— pop()μ—μ„œ ν˜• λ³€ν™˜μ΄ ν•„μš”ν•œλ°, μ΄λ•Œλ„ @SuppressWarnings("unchecked") μ–΄λ…Έν…Œμ΄μ…˜μ„ μΆ”κ°€ν•˜μ—¬ κ²½κ³ λ₯Ό 숨길 수 μžˆλ‹€. 이 κ²½μš°μ—λ„ μ•ˆμ „ν•œ μ΄μœ λŠ” μœ„μ™€ λ™μΌν•˜λ‹€.

이 방법은 ν˜•λ³€ν™˜μ„ ν•˜λŠ” 뢀뢄이 λ§Žμ•„ 질 수 μžˆμ–΄ 가독성이 떨어지고, elements λ°°μ—΄ 생성 μ‹œ 맀번 ν˜•λ³€ν™˜μ„ ν•΄μ•Όν•˜κΈ° λ•Œλ¬Έμ— λ²ˆκ±°λ‘­λ‹€. ν•˜μ§€λ§Œ 그만큼 ν˜• λ³€ν™˜μ˜ λ²”μœ„κ°€ μ΅œμ†Œν™”λ˜κ³  νž™ μ˜€μ—Όμ˜ μœ„μΉ˜λ„ μ΅œμ†Œν™”λ˜κΈ° λ•Œλ¬Έμ— νž™ μ˜€μ—Όμ— λŒ€ν•΄ 더 μ•ˆμ „ν•˜λ‹€.

μ œν•œμ΄ ν•„μš”ν•œ μ œλ„€λ¦­

μ œλ„€λ¦­νƒ€μž…μ€ 기본적으둜 νƒ€μž… λ§€κ°œλ³€μˆ˜μ— μ•„λ¬΄λŸ° μ œμ•½μ„ 두지 μ•ŠκΈ° λ•Œλ¬Έμ— λͺ¨λ“  νƒ€μž…μ„ μˆ˜μš©ν•  수 μžˆλ‹€. ν•˜μ§€λ§Œ ν•„μš”μ— 따라 νŠΉμ • νƒ€μž…λ§Œ μˆ˜μš©ν•˜λ„λ‘ μƒν™©μ—λŠ” μ œν•œμ„ λ‘λŠ” 것이 μ’‹λ‹€.

// Delayed 클래슀의 ν•˜μœ„ 클래슀만 μˆ˜μš©ν•˜λ„λ‘ μ œν•œμ„ 두어 νƒ€μž… μ•ˆμ „μ„±μ„ 보μž₯
public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
        implements BlockingQueue<E> {
    // ...
}

Last updated