Item 28. List vs Array

๋ฐฐ์—ด๋ณด๋‹ค๋Š” ๋ฆฌ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ผ

์•„์ดํ…œ์˜ ์ฃผ์ œ์ฒ˜๋Ÿผ ๋ฐฐ์—ด๋ณด๋‹ค๋Š” ๋ฆฌ์ŠคํŠธ๋ฅผ ์šฐ์„ ํ•ด์•ผํ•˜์ง€๋งŒ ๋ฌด์กฐ๊ฑด์ ์œผ๋กœ ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•˜์ง€ ๋ง๋ผ๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ๋ฆฌ์ŠคํŠธ๋Š” ๊ฒฐ๊ตญ Java ๊ธฐ๋ณธ ํƒ€์ž…์ด ์•„๋‹ˆ๋ฉฐ(๋‚ด๋ถ€ ๊ตฌํ˜„์—์„œ ๋ฐฐ์—ด ์‚ฌ์šฉ), ์„ฑ๋Šฅ์ด ์ค‘์š”ํ•œ ์ƒํ™ฉ(HashMap)์—์„œ๋Š” ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ๊ผญ ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•ด์•ผํ•˜๋Š” ์ƒํ™ฉ์ด ์•„๋‹ˆ๋ผ๋ฉด ๋ฆฌ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

๋ฐฐ์—ด๊ณผ ์ œ๋„ค๋ฆญ ํƒ€์ž…์˜ ์ฐจ์ด

๋ฐฐ์—ด๊ณผ ์ œ๋„ค๋ฆญ ํƒ€์ž… ์‚ฌ์ด์˜ ํฐ ์ฐจ์ด๋กœ๋Š” ๊ณต๋ณ€๊ณผ ์‹ค์ฒดํ™”๊ฐ€ ์žˆ๋Š”๋ฐ, ์ž์„ธํžˆ ์•Œ์•„๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

๊ณต๋ณ€(covariant)

Sub๊ฐ€ Super์˜ ํ•˜์œ„ ํƒ€์ž…์ด๋ผ๋ฉด ๋ฐฐ์—ด Sub[]๋Š” ๋ฐฐ์—ด Super[]์˜ ํ•˜์œ„ ํƒ€์ž…์ด ๋˜์ง€๋งŒ, ์ œ๋„ค๋ฆญ ํƒ€์ž… List๋Š” List์˜ ํ•˜์œ„ ํƒ€์ž…์ด ๋˜์ง€ ์•Š์œผ๋ฉฐ, ์ƒ์œ„ ํƒ€์ž…๋„ ์•„๋‹ˆ๋‹ค.

class Main {

    public static void main(String[] args) {
        Object[] objectArray = new Long[1];
        objectArray[0] = "I don't fit in"; // ๋Ÿฐํƒ€์ž„ ์—๋Ÿฌ, ArrayStoreException

        List<Object> ol = new ArrayList<Long>(); // ์ปดํŒŒ์ผ ์—๋Ÿฌ, Incompatible types
        ol.add("I don't fit in");
    }
}

์ด ์ฐจ์ด๋Š” ์œ„ ์ฝ”๋“œ์—์„œ ์•Œ ์ˆ˜ ์žˆ๋“ฏ์ด ๋ฐฐ์—ด์€ ๊ณต๋ณ€์„ ํ—ˆ์šฉํ•˜์—ฌ ๋Ÿฐํƒ€์ž„์— ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€๋งŒ, ์ œ๋„ค๋ฆญ์€ ์ปดํŒŒ์ผ ์‹œ์— ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์—ฌ ๋ณด๋‹ค ์•ˆ์ „ํ•˜๋‹ค.

์‹ค์ฒดํ™”(reify)

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋ฐฐ์—ด์€ ์‹ค์ฒดํ™”๋˜๊ณ , ์ œ๋„ค๋ฆญ์€ ์‹ค์ฒดํ™”๋˜์ง€ ์•Š๋Š” ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค. ์ด ์ฐจ์ด๋กœ ์œ„ ์ฝ”๋“œ์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์ฐจ์ด๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • ๋ฐฐ์—ด: ๋Ÿฐํƒ€์ž„์—๋„ ์ž์‹ ์ด ๋‹ด๊ธฐ๋กœ ํ•œ ์›์†Œ์˜ ํƒ€์ž…์„ ์ธ์ง€ํ•˜๊ณ  ํ™•์ธํ•˜์—ฌ ArrayStoreException์„ ๋ฐœ์ƒ์‹œํ‚ด

  • ์ œ๋„ค๋ฆญ: ์ œ๋„ค๋ฆญ์€ ํƒ€์ž… ์ •๋ณด๋ฅผ ์ปดํŒŒ์ผ ํƒ€์ž„์—๋งŒ ๊ฒ€์‚ฌํ•˜๊ณ ๋Ÿฐํƒ€์ž„์— ์†Œ๊ฑฐ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋Ÿฐํƒ€์ž„์—๋Š” ํƒ€์ž… ์ •๋ณด๋ฅผ ์•Œ ์ˆ˜ ์—†์Œ

    • E, List<E>, List<String> ๊ฐ™์€ ํƒ€์ž…์„ ์‹ค์ฒดํ™” ๋ถˆ๊ฐ€ ํƒ€์ž…(non-reifiable type)์ด๋ผ๊ณ  ํ•จ

    • ์‹ค์ฒดํ™” ๋˜์ง€ ์•Š์•„ ๋Ÿฐํƒ€์ž„์— ์ปดํŒŒ์ผํƒ€์ž„๋ณด๋‹ค ํƒ€์ž… ์ •๋ณด๋ฅผ ์ ๊ฒŒ ๊ฐ€์ง€๊ณ  ์žˆ์Œ

    • ๋งค๊ฐœ๋ณ€์ˆ˜ํ™” ํƒ€์ž…์„ ์‹ค์ฒดํ™”ํ•  ์ˆ˜ ์žˆ๋Š” ํƒ€์ž…์€ ๋น„ํ•œ์ •์  ์™€์ผ๋“œ์นด๋“œ(List<?>, Map<?, ?> ๋“ฑ)ํƒ€์ž…์œผ๋กœ ํ•œ์ •๋จ

์ด์ฒ˜๋Ÿผ ๊ณต๋ณ€/์‹ค์ฒดํ™”์— ์žˆ์–ด ์„œ๋กœ ๋ฐ˜๋Œ€๋˜๋Š” ์„ฑ์งˆ์„ ๊ฐ€์ง€๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฐฐ์—ด๊ณผ ์ œ๋„ค๋ฆญ์€ ์ž˜ ์–ด์šฐ๋Ÿฌ์ง€์ง€ ๋ชปํ•œ๋‹ค.

์ œ๋„ค๋ฆญ ๋ฐฐ์—ด

์ด์ฒ˜๋Ÿผ ์ž˜ ์–ด์šฐ๋Ÿฌ์ง€๊ธฐ ํž˜๋“ค๊ธฐ ๋•Œ๋ฌธ์— ์ œ๋„ค๋ฆญ ๋ฐฐ์—ด์„ ๋งŒ๋“œ๋ ค๊ณ  ์‹œ๋„ํ•˜๋ฉด ์ปดํŒŒ์ผ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ๋งŒ์•ฝ ์ด๋ฅผ ํ—ˆ์šฉํ•˜๊ณ  1๋ฒˆ ๋ผ์ธ ์ฝ”๋“œ์—์„œ ์ปดํŒŒ์ผ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋Š” ๊ฒฝ์šฐ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

class Main {

    public static void main(String[] args) {
        List<String>[] stringLists = new List<String>[1]; // 1. ์ œ๋„ค๋ฆญ ๋ฐฐ์—ด ์ƒ์„ฑ
        List<Integer> intList = List.of(42); // 2. ์›์†Œ๊ฐ€ ํ•˜๋‚˜์ธ ๋ฆฌ์ŠคํŠธ ์ƒ์„ฑ
        Object[] objects = stringLists; // 3. Object ๋ฐฐ์—ด์— List<String> ๋ฐฐ์—ด์„ ๋Œ€์ž…(๋ฐฐ์—ด์€ ๊ณต๋ณ€์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ€๋Šฅ)
        objects[0] = intList; // 4. Object ๋ฐฐ์—ด์˜ ์ฒซ ๋ฒˆ์งธ ์›์†Œ์— 2๋ฒˆ์—์„œ ์ƒ์„ฑํ•œ intList๋ฅผ ๋Œ€์ž…(๋Ÿฐํƒ€์ž„์—์„œ List<Integer> -> List raw type์œผ๋กœ ๋ณ€ํ™˜๋˜์–ด ๊ฐ€๋Šฅ)
        String s = stringLists[0].get(0); // ์ปดํŒŒ์ผ ์—๋Ÿฌ
        // stringLists[0]์— ์ €์žฅ๋œ List<Integer> ์ธ์Šคํ„ด์Šค์—์„œ ์ฒซ ๋ฒˆ์งธ ์›์†Œ์ธ 5๋Š” Integer์ด๊ธฐ ๋•Œ๋ฌธ์— String์œผ๋กœ ํ˜•๋ณ€ํ™˜ํ•  ์ˆ˜ ์—†์Œ
    }
}

์ด์ฒ˜๋Ÿผ ์˜ˆ์ƒ์น˜ ๋ชป ํ•œ ๋Ÿฐํƒ€์ž„ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ž๋ฐ” ์ปดํŒŒ์ผ๋Ÿฌ์—์„œ๋Š” 1๋ฒˆ ๋ผ์ธ์˜ ์ œ๋„ค๋ฆญ ๋ฐฐ์—ด์„ ์ƒ์„ฑํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ปดํŒŒ์ผ ์—๋Ÿฌ๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค.

์‹ค์ฒดํ™” ๋ถˆ๊ฐ€ ํƒ€์ž…

์‹ค์ฒดํ™” ๋ถˆ๊ฐ€ ํƒ€์ž…์œผ๋กœ ๋ฐฐ์—ด์„ ์ƒ์„ฑํ•˜๋Š” ๊ฒฝ์šฐ ์ปดํŒŒ์ผ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€๋Š” ์•Š์ง€๋งŒ ๊ฒฝ๊ณ ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.(ํƒ€์ž… ์•ˆ์ „์„ฑ์ด ๋ณด์žฅ๋˜์ง€ ์•Š์Œ์„ ์•Œ๋ ค์คŒ)

class Chooser<T> {
    private final T[] choiceArray;

    public Chooser(Collection<T> choices) {
        choiceArray = (T[]) choices.toArray();
    }

    public T choose() {
        Random random = ThreadLocalRandom.current();
        return choiceArray[random.nextInt(choiceArray.length)];
    }
}

์œ„ ์ฝ”๋“œ์—์„œ๋Š” ์ •์ƒ์ ์œผ๋กœ ์ปดํŒŒ์ผ ๋˜๊ณ , ๋Ÿฐํƒ€์ž„์—์„œ๋„ ๋ฐœ์ƒํ•˜์ง€๋Š” ์•Š์•„ ์•ˆ์ „ํ•˜๋‹ค๊ณ  ํ™•์‹ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ์—” @SuppressWarnings("unchecked") ์–ด๋…ธํ…Œ์ด์…˜์„ ์ถ”๊ฐ€ํ•˜์—ฌ ๊ฒฝ๊ณ ๋ฅผ ์ˆจ๊ธธ ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด ๋ฐฉ๋ฒ•๋ณด๋‹ค๋Š” ์„ฑ๋Šฅ ์ƒ ์†ํ•ด๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์ง€๋งŒ ๋ฆฌ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฒฝ๊ณ ์˜ ์›์ธ์„ ์ œ๊ฑฐํ•˜๋Š” ๊ฒƒ์ด ๋” ์ข‹๋‹ค.

class Chooser<T> {
    private final List<T> choiceList;

    public Chooser(Collection<T> choices) {
        choiceList = new ArrayList<>(choices);
    }

    public T choose() {
        Random random = ThreadLocalRandom.current();
        return choiceList.get(random.nextInt(choiceList.size()));
    }
}

Last updated