๐Ÿ“‚ JAVA/์ดํŽ™ํ‹ฐ๋ธŒ ์ž๋ฐ”

ํ•œ์ •์  ์™€์ผ๋“œ์นด๋“œ๋ฅผ ์‚ฌ์šฉํ•ด API ์œ ์—ฐ์„ฑ์„ ๋†’์ด๋ผ - [5์žฅ. ์ œ๋„ค๋ฆญ(์•„์ดํ…œ31)]

Amenable 2023. 6. 1. 20:48

1. PECS ๐ŸŒž

  PECS(Producer-Extends, Consumer-Super)๋ž€ ๋งค๊ฐœ๋ณ€์ˆ˜ํ™” ํƒ€์ž… T๊ฐ€ ์ƒ์‚ฐ์ž๋ผ๋ฉด <? extends T>๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , ์†Œ๋น„์ž๋ผ๋ฉด <? super T>๋ฅผ ์‚ฌ์šฉํ•˜๋ผ๋Š” ๊ฒƒ์ด๋‹ค.

  ์˜ˆ์‹œ์™€ ํ•จ๊ป˜ PECS๋ฅผ ์ดํ•ดํ•ด ๋ณด๋„๋ก ํ•˜์ž.

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

    // ๋ฐฐ์—ด elements๋Š” push(E)๋กœ ๋„˜์–ด์˜จ E ์ธ์Šคํ„ด์Šค๋งŒ ๋‹ด๋Š”๋‹ค.
    // ๋”ฐ๋ผ์„œ ํƒ€์ž… ์•ˆ์ „์„ฑ์„ ๋ณด์žฅํ•˜์ง€๋งŒ,
    // ์ด ๋ฐฐ์—ด์˜ ๋Ÿฐํƒ€์ž„ ํƒ€์ž…์€ E[]๊ฐ€ ์•„๋‹Œ Object[]๋‹ค!
    @SuppressWarnings("unchecked")
    public Stack() {
        elements = (E[]) 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 = 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);
        }
    }

    public void pushAll(Iterable<E> src) {
        for(E e : src)
            push(e);
    }

    public void popAll(Collection<E> dst) {
        while(!isEmpty())
            dst.add(pop());
    }
}

  ์ฝ”๋“œ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์ง€๊ธˆ๊นŒ์ง€๋Š” ํƒ€์ž…๋งค๊ฐœ๋ณ€์ˆ˜ E๋งŒ์„ ์‚ฌ์šฉํ•˜์˜€๋‹ค. ์ฆ‰, ํ•˜๋‚˜์˜ ํƒ€์ž…๋งŒ ์ง€์ •ํ•ด์„œ ์‚ฌ์šฉํ•œ ๊ฒƒ์ด๋‹ค.

  ์ œ๋„ค๋ฆญ์€ ๋ถˆ๊ณต๋ณ€์ด๊ธฐ ๋•Œ๋ฌธ์— ์•„๋ž˜ ์ฝ”๋“œ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋‹ค๋ฅธ ํƒ€์ž…์„ ๋„ฃ์ง€ ๋ชปํ•˜๊ฒŒ ๋œ๋‹ค.

public static void main(String[] args) {
    Stack<Number> numberStack = new Stack<>();

    Iterable<Number> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
    numberStack.pushAll(numbers); // ๊ฐ€๋Šฅ 

    Iterable<Integer> integers = Arrays.asList(1, 2, 3, 4, 5, 6);
    numberStack.pushAll(integers); // ๋ถˆ๊ฐ€๋Šฅ // ์ปดํŒŒ์ผ ์—๋Ÿฌ
}

  ํ•˜์ง€๋งŒ, ์ผ๋ฐ˜์ ์œผ๋กœ Stack<Number>์— Integer๋ฅผ ๋„ฃ๋Š” ๊ฒƒ์ด ๋ฌธ์ œ๊ฐ€ ๋˜์ง€๋Š” ์•Š๋Š”๋‹ค ํ•ด๋‹นํ•˜๋Š” ๊ฐ์ฒด์˜ ์ƒ์œ„ ํƒ€์ž…์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์•„๋ฌด๋Ÿฐ ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

  ๊ทธ๋ž˜์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ํ•œ์ •์  ์™€์ผ๋“œ์นด๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

// ๊ธฐ์กด
public void pushAll(Iterable<E> src) {
    for(E e : src)
        push(e);
}


// ๋ณ€๊ฒฝ - ํ•œ์ •์  ์™€์ผ๋“œ์นด๋“œ ์‚ฌ์šฉ
public void pushAll(Iterable<? extends E> src) {
    for(E e : src)
        push(e);
}
public static void main(String[] args) {
    Stack<Number> numberStack = new Stack<>();

    Iterable<Integer> integers = Arrays.asList(1, 2, 3, 4, 5, 6);
    numberStack.pushAll(integers);

    Iterable<Double> doubles = Arrays.asList(1.0, 2.1, 3.2, 4.3, 5.4, 6.5);
    numberStack.pushAll(doubles);
}

  ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด Number์˜ ํ•˜์œ„ ํƒ€์ž…๋“ค์„ ๋„ฃ์„ ์ˆ˜ ์žˆ๋‹ค.

  ์ด๋Ÿฌํ•œ ์—ญํ• ์„ ํ•˜๋Š” ๊ฒƒ์„ ์ƒ์‚ฐ์ž(Producer)๋ผ๊ณ  ํ•˜๋Š”๋ฐ ์ƒ์‚ฐ์ž์—์„œ๋Š” extends๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” E์˜ ํ•˜์œ„ ํƒ€์ž…์„ ๋ฐ›์•„์„œ ๋„ฃ์–ด๋„ ๋ฌธ์ œ๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค

 

  pushAll๋กœ ๋„ฃ๋Š” ๊ฒƒ์„ ์‚ดํŽด๋ณด์•˜์œผ๋ฏ€๋กœ ๊บผ๋‚ด๋Š” ๊ฒƒ์ธ popAll๋„ ์‚ดํŽด๋ณด๋„๋ก ํ•˜์ž

  ๊บผ๋‚ผ ๋•Œ์—๋Š” ํ•ด๋‹น ํƒ€์ž… E๋ณด๋‹ค ๋” ์ƒ์œ„ ํƒ€์ž…์œผ๋กœ ๊บผ๋‚ผ ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด E๊ฐ€ Number์ธ ๊ฒฝ์šฐ Object๋กœ ๊บผ๋‚ผ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

  ํ•˜์ง€๋งŒ ์•„๋ž˜์™€ ๊ฐ™์ด ํ˜„์žฌ๋Š” ํƒ€์ž… ํ•˜๋‚˜๋กœ ์„ ์–ธ์ด ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์šฐ๋ฆฌ์˜ ์˜๋„๋Œ€๋กœ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•œ๋‹ค.

// ๊ธฐ์กด
public void pushAll(Iterable<E> src) {
    for(E e : src)
        push(e);
}

  ๊ทธ๋ž˜์„œ ์ด๋Ÿฐ ๊ฒฝ์šฐ์—๋„ ํ•œ์ •์  ์™€์ผ๋“œ์นด๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

// ๋ณ€๊ฒฝ - ํ•œ์ •์  ์™€์ผ๋“œ์นด๋“œ ์‚ฌ์šฉ
public void pushAll(Iterable<? extends E> src) {
    for(E e : src)
        push(e);
}
public static void main(String[] args) {
    Stack<Number> numberStack = new Stack<>();

    Collection<Object> objects = new ArrayList<>();
    numberStack.popAll(objects);
}

  ์ฆ‰, ์ด๋ ‡๊ฒŒ pushAll๊ณผ ๊ฐ™์ด ์ƒ์‚ฐ์ž(Provider) ์—ญํ• ์„ ํ•  ๋•Œ์—๋Š” extends๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  popAll๊ณผ ๊ฐ™์ด ์†Œ๋น„์ž(Consumer) ์—ญํ• ์„ ํ•  ๋•Œ์—๋Š” super๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

  ์ด๊ฒƒ์ด PECS(Producer-Extends, Consumer-Super) ๊ทœ์น™์ด๋‹ค.

 

 

2. ํƒ€์ž… ๋งค๊ฐœ๋ณ€์ˆ˜ VS ์™€์ผ๋“œ์นด๋“œ ๐ŸŒ

  ํƒ€์ž… ๋งค๊ฐœ๋ณ€์ˆ˜์™€ ์™€์ผ๋“œ์นด๋“œ์—๋Š” ๊ณตํ†ต๋˜๋Š” ๋ถ€๋ถ„์ด ์žˆ์–ด์„œ, ๋ฉ”์„œ๋“œ๋ฅผ ์ •์˜ํ•  ๋•Œ ๋‘˜ ์ค‘ ์–ด๋А ๊ฒƒ์„ ์‚ฌ์šฉํ•ด๋„ ๊ดœ์ฐฎ์„ ๋•Œ๊ฐ€ ๋งŽ๋‹ค.

  swap์ด๋ผ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ •์˜ํ•œ๋‹ค๊ณ  ํ•  ๋•Œ ์•„๋ž˜์™€ ๊ฐ™์ด ๋‘ ๊ฐ€์ง€ ๋ฐฉ์‹์œผ๋กœ ์„ ์–ธํ•  ์ˆ˜ ์žˆ๋‹ค.

// ํƒ€์ž… ๋งค๊ฐœ๋ณ€์ˆ˜ ์‚ฌ์šฉ
public static <E> void swap(List<E> list, int i, int j);
// ์™€์ผ๋“œ์นด๋“œ ์‚ฌ์šฉ
public static void swap(List<?> list, int i, int j);

  ๋งŒ์•ฝ public API๋ผ๊ณ  ํ•œ๋‹ค๋ฉด ๋‘ ๋ฒˆ์งธ๊ฐ€ ๋‚ซ๋‹ค. ์–ด๋–ค ๋ฆฌ์ŠคํŠธ๋“  ์ด ๋ฉ”์„œ๋“œ์— ๋„˜๊ธฐ๋ฉด ๋ช…์‹œํ•œ ์ธ๋ฑ์Šค์˜ ์›์†Œ๋“ค์„ ๊ตํ™˜ํ•ด ์ค„ ๊ฒƒ์ด๊ณ , ์‹ ๊ฒฝ ์จ์•ผ ํ•  ํƒ€์ž… ๋งค๊ฐœ๋ณ€์ˆ˜๋„ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

  ๊ธฐ๋ณธ ๊ทœ์น™์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค. ๋ฉ”์„œ๋“œ ์„ ์–ธ์— ํƒ€์ž… ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ํ•œ ๋ฒˆ๋งŒ ๋‚˜์˜ค๋ฉด ์™€์ผ๋“œ์นด๋“œ๋กœ ๋Œ€์ฒดํ•˜๋ผ๋Š” ๊ฒƒ์ด๋‹ค.

  ์ด๋•Œ ๋น„ํ•œ์ •์  ํƒ€์ž… ๋งค๊ฐœ๋ณ€์ˆ˜๋ผ๋ฉด ๋น„ํ•œ์ •์  ์™€์ผ๋“œ์นด๋“œ๋กœ ๋ฐ”๊พธ๊ณ , ํ•œ์ •์  ํƒ€์ž… ๋งค๊ฐœ๋ณ€์ˆ˜๋ผ๋ฉด ํ•œ์ •์  ์™€์ผ๋“œ์นด๋“œ๋กœ ๋ฐ”๊พธ๋ฉด ๋œ๋‹ค.

  ํ•˜์ง€๋งŒ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ตฌํ˜„ํ•˜๋ฉด ์ปดํŒŒ์ผ๋˜์ง€ ์•Š๋Š”๋‹ค.

public class Swap {

    public static void swap(List<?> list, int i, int j) {
        list.set(i, list.set(j, list.get(i)));
    }
}

  List<?>์—๋Š” null ์™ธ์—๋Š” ์–ด๋–ค ๊ฐ’๋„ ๋„ฃ์„ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ทธ๋ž˜์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ๋„์šฐ๋ฏธ ๋ฉ”์„œ๋“œ๋ฅผ ๋”ฐ๋กœ ์ž‘์„ฑํ•ด์„œ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

public class Swap {

    public static void swap(List<?> list, int i, int j) {
        swapHelper(list, i, j);
    }

    private static <E> void swapHelper(List<E> list, int i, int j){
        list.set(i, list.set(j, list.get(i)));
    }
}

 

ํ•ด๋‹น ๊ธ€์€ ๋ฐฑ๊ธฐ์„  ๋‹˜์˜ '์ดํŽ™ํ‹ฐ๋ธŒ ์ž๋ฐ” ์™„๋ฒฝ ๊ณต๋žต'์„ ์ฐธ๊ณ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.