item 13 dodo4513 - JAVA-JIKIMI/EFFECTIVE-JAVA3 GitHub Wiki

์•„์ดํ…œ13 clone ์žฌ์ •์˜๋Š” ์ฃผ์˜ํ•ด์„œ ์ง„ํ–‰ํ•˜๋ผ

Cloneable ์˜ ๋ฌธ์ œ์ 

  • Cloneable์€ ๋ณต์ œํ•ด๋„ ๋˜๋Š” ํด๋ž˜์Šค์ž„์„ ๋ช…์‹œํ•˜๋Š” ์šฉ๋„์˜ ๋ฏน์Šค์ธ ์ธํ„ฐํŽ˜์ด์Šค์ง€๋งŒ, ์•„์‰ฝ๊ฒŒ๋„ ์˜๋„ํ•œ ๋ชฉ์ ์„ ์ œ๋Œ€๋กœ ์ด๋ฃจ์ง€ ๋ชปํ–ˆ๋‹ค. ๊ฐ€์žฅ ํฐ ๋ฌธ์ œ๋Š” clone ๋ฉ”์„œ๋“œ๊ฐ€ ์„ ์–ธ๋œ ๊ณณ์ด Cloneable์ด ์•„๋‹Œ Object์ด๊ณ , ๊ทธ๋งˆ์ €๋„ protected๋ผ๋Š” ๋ฐ ์žˆ๋‹ค. ๊ทธ๋ž˜์„œ Cloneable์„ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ๋งŒ์œผ๋กœ๋Š” ์™ธ๋ถ€ ๊ฐ์ฒด์—์„œ clone ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†๋‹ค. ๋ฆฌํ”Œ๋ ‰์…˜(์•„์ดํ…œ 65)์„ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, 100% ์„ฑ๊ณตํ•˜๋Š” ๊ฒƒ๋„ ์•„๋‹ˆ๋‹ค. ํ•ด๋‹น ๊ฐ์ฒด๊ฐ€ ์ ‘๊ทผ์ด ํ—ˆ์šฉ๋œ clone ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•œ๋‹ค๋Š” ๋ณด์žฅ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

  • ์œ„์™€ ๊ฐ™์€ ๋ฌธ์ œ์ ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  Cloneable ๋ฐฉ์‹์€ ๋„๋ฆฌ ์“ฐ์ด๊ณ  ์žˆ์–ด์„œ ์ž˜ ์•Œ์•„๋‘๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ์ด๋ฒˆ ์•„์ดํ…œ์—์„œ๋Š” clone ๋ฉ”์„œ๋“œ๋ฅผ ์ž˜ ๋™์ž‘ํ•˜๊ฒŒ๋” ํ•ด์ฃผ๋Š” ๊ตฌํ˜„ ๋ฐฉ๋ฒ•๊ณผ ์–ธ์ œ ๊ทธ๋ ‡๊ฒŒ ํ•ด์•ผ ํ•˜๋Š”์ง€๋ฅผ ์•Œ๋ ค์ฃผ๊ณ , ๊ฐ€๋Šฅํ•œ ๋‹ค๋ฅธ ์„ ํƒ์ง€์— ๊ด€ํ•ด ๋…ผ์˜ํ•˜๊ฒ ๋‹ค.

  • ๋ช…์„ธ์—์„œ๋Š” ์ด์•ผ๊ธฐํ•˜์ง€ ์•Š์ง€๋งŒ ์‹ค๋ฌด์—์„œ Cloneable์„ ๊ตฌํ˜„ํ•œ ํด๋ž˜์Šค๋Š” clone ๋ฉ”์„œ๋“œ๋ฅผ public์œผ๋กœ ์ œ๊ณตํ•˜๋ฉฐ, ์‚ฌ์šฉ์ž๋Š” ๋‹น์—ฐํžˆ ๋ณต์ œ๊ฐ€ ์ œ๋Œ€๋กœ ์ด๋ค„์ง€๋ฆฌ๋ผ ๊ธฐ๋Œ€ํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜...

clone์˜ ํ—ˆ์ˆ ํ•œ ๋ช…์„ธ

์ด ๊ฐ์ฒด์˜ ๋ณต์‚ฌ๋ณธ์„ ์ƒ์„ฑํ•ด ๋ฐ˜ํ™˜ํ•œ๋‹ค.
โ€˜๋ณต์‚ฌโ€™์˜ ์ •ํ™•ํ•œ ๋œป์€ ๊ทธ ๊ฐ์ฒด๋ฅผ ๊ตฌํ˜„ํ•œ ํด๋ž˜์Šค์— ๋”ฐ๋ผ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค.
์ผ๋ฐ˜์ ์ธ ์˜๋„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.
์–ด๋–ค ๊ฐ์ฒด x์— ๋Œ€ํ•ด ๋‹ค์Œ ์‹์€ ์ฐธ์ด๋‹ค.
x.clone() != x
๋˜ํ•œ ๋‹ค์Œ ์‹๋„ ์ฐธ์ด๋‹ค.
x.clone().getClass() == x.getClass()
ํ•˜์ง€๋งŒ ์ด์ƒ์˜ ์š”๊ตฌ๋ฅผ ๋ฐ˜๋“œ์‹œ ๋งŒ์กฑํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค.
ํ•œํŽธ ๋‹ค์Œ ์‹๋„ ์ผ๋ฐ˜์ ์œผ๋กœ ์ฐธ์ด์ง€๋งŒ, ์—ญ์‹œ ํ•„์ˆ˜๋Š” ์•„๋‹ˆ๋‹ค.
x.clone().equals(x)
๊ด€๋ก€์ƒ, ์ด ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฐ์ฒด๋Š” super.clone์„ ํ˜ธ์ถœํ•ด ์–ป์–ด์•ผ ํ•œ๋‹ค.
์ด ํด๋ž˜์Šค์™€ (Object๋ฅผ ์ œ์™ธํ•œ) ๋ชจ๋“  ์ƒ์œ„ ํด๋ž˜์Šค๊ฐ€ ์ด ๊ด€๋ก€๋ฅผ ๋”ฐ๋ฅธ๋‹ค๋ฉด ๋‹ค์Œ ์‹์€ ์ฐธ์ด๋‹ค.
x.clone().getClass() == x.getClass()
๊ด€๋ก€์ƒ, ๋ฐ˜ํ™˜๋œ ๊ฐ์ฒด์™€ ์›๋ณธ ๊ฐ์ฒด๋Š” ๋…๋ฆฝ์ ์ด์–ด์•ผ ํ•œ๋‹ค.
์ด๋ฅผ ๋งŒ์กฑํ•˜๋ ค๋ฉด super.clone์œผ๋กœ ์–ป์€ ๊ฐ์ฒด์˜ ํ•„๋“œ ์ค‘ ํ•˜๋‚˜ ์ด์ƒ์„ ๋ฐ˜ํ™˜ ์ „์— ์ˆ˜์ •ํ•ด์•ผ ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

  • ๊ฐ•์ œ์„ฑ์ด ์—†๋‹ค๋Š” ์ ๋งŒ ๋นผ๋ฉด ์ƒ์„ฑ์ž ์—ฐ์‡„(constructor chaining)์™€ ์‚ด์ง ๋น„์Šทํ•œ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด๋‹ค. ์ฆ‰, clone ๋ฉ”์„œ๋“œ๊ฐ€ super.clone์ด ์•„๋‹Œ, ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•ด ์–ป์€ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•ด๋„ ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ๋ถˆํ‰ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ด๋‹ค.
  • ํ•˜์ง€๋งŒ ์ด ํด๋ž˜์Šค์˜ ํ•˜์œ„ ํด๋ž˜์Šค์—์„œ super.clone์„ ํ˜ธ์ถœํ•œ๋‹ค๋ฉด ์ž˜๋ชป๋œ ํด๋ž˜์Šค์˜ ๊ฐ์ฒด๊ฐ€ ๋งŒ๋“ค์–ด์ ธ, ๊ฒฐ๊ตญ ํ•˜์œ„ ํด๋ž˜์Šค์˜ clone ๋ฉ”์„œ๋“œ๊ฐ€ ์ œ๋Œ€๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š๊ฒŒ ๋œ๋‹ค.

clone ๊ตฌํ˜„ํ•˜๊ธฐ

๊ฐ„๋‹จํ•œ ์ผ€์ด์Šค

@Override public PhoneNumber clone() {
    try {
        return (PhoneNumber) super.clone();
    } catch (CloneNotSupportedException e) {
        throw new AssertionError(); // ์ผ์–ด๋‚  ์ˆ˜ ์—†๋Š” ์ผ์ด๋‹ค.
    }
}
  • ๊ฐ€๋ณ€ ์ƒํƒœ๋ฅผ ์ฐธ์กฐํ•˜์ง€ ์•Š๋Š” ํด๋ž˜์Šค์šฉ clone ๋ฉ”์„œ๋“œ๋Š” ์œ„์™€ ๊ฐ™์ด ์‹ฌํ”Œํ•˜๋‹ค.

๊ฐ€๋ณ€ ์ƒํƒœ๊ฐ€ ์žˆ๋Š” ์ผ€์ด์Šค

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

    public Stack() {
        this.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;
    }

    // ๊ฐ€๋ณ€ ์ƒํƒœ๋ฅผ ์ฐธ์กฐํ•˜์ง€ ์•Š๋Š” ํด๋ž˜์Šค์šฉ clone ๋ฉ”์„œ๋“œ
    @Override
    public Stack clone() {
        try {
            return (Stack) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }

    private void ensureCapacity() {
        if (elements.length == size) {
            elements = Arrays.copyOf(elements, 2 * size + 1);
        }
    }
}
  1. ์ด ํด๋ž˜์Šค๋ฅผ ๋ณต์ œํ•  ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“ค์–ด๋ณด์ž.
  2. clone ๋ฉ”์„œ๋“œ๊ฐ€ ๋‹จ์ˆœํžˆ super.clone์˜ ๊ฒฐ๊ณผ๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ํ•œ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ? ๋ฐ˜ํ™˜๋œ Stack ์ธ์Šคํ„ด์Šค์˜ size ํ•„๋“œ๋Š” ์˜ฌ๋ฐ”๋ฅธ ๊ฐ’์„ ๊ฐ–๊ฒ ์ง€๋งŒ, elements ํ•„๋“œ๋Š” ์›๋ณธ Stack ์ธ์Šคํ„ด์Šค์™€ ๋˜‘๊ฐ™์€ ๋ฐฐ์—ด์„ ์ฐธ์กฐํ•  ๊ฒƒ์ด๋‹ค.
  3. ์›๋ณธ์ด๋‚˜ ๋ณต์ œ๋ณธ ์ค‘ ํ•˜๋‚˜๋ฅผ ์ˆ˜์ •ํ•˜๋ฉด ๋‹ค๋ฅธ ํ•˜๋‚˜๋„ ์ˆ˜์ •๋˜์–ด ๋ถˆ๋ณ€์‹์„ ํ•ด์นœ๋‹ค๋Š” ์ด์•ผ๊ธฐ๋‹ค. ๋”ฐ๋ผ์„œ ํ”„๋กœ๊ทธ๋žจ์ด ์ด์ƒํ•˜๊ฒŒ ๋™์ž‘ํ•˜๊ฑฐ๋‚˜ NullPointerException์„ ๋˜์งˆ ๊ฒƒ์ด๋‹ค.
// ๊ฐ€๋ณ€ ์ƒํƒœ๋ฅผ ์ฐธ์กฐํ•˜๋Š” ํด๋ž˜์Šค์šฉ clone ๋ฉ”์„œ๋“œ
@Override
public Stack clone() {
    try {
        Stack result = (Stack) super.clone();
        result.elements = elements.clone();
        return result;
    } catch (CloneNotSupportedException e) {
        throw new AssertionError();
    }
}
  • Stack ํด๋ž˜์Šค์˜ ํ•˜๋‚˜๋ฟ์ธ ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค๋ฉด ์ด๋Ÿฌํ•œ ์ƒํ™ฉ์€ ์ ˆ๋Œ€ ์ผ์–ด๋‚˜์ง€ ์•Š๋Š”๋‹ค. clone ๋ฉ”์„œ๋“œ๋Š” ์‚ฌ์‹ค์ƒ ์ƒ์„ฑ์ž์™€ ๊ฐ™์€ ํšจ๊ณผ๋ฅผ ๋‚ธ๋‹ค. ์ฆ‰, clone์€ ์›๋ณธ ๊ฐ์ฒด์— ์•„๋ฌด๋Ÿฐ ํ•ด๋ฅผ ๋ผ์น˜์ง€ ์•Š๋Š” ๋™์‹œ์— ๋ณต์ œ๋œ ๊ฐ์ฒด์˜ ๋ถˆ๋ณ€์‹์„ ๋ณด์žฅํ•ด์•ผ ํ•œ๋‹ค. ๊ทธ๋ž˜์„œ Stack์˜ clone ๋ฉ”์„œ๋“œ๋Š” ์ œ๋Œ€๋กœ ๋™์ž‘ํ•˜๋ ค๋ฉด ์Šคํƒ ๋‚ด๋ถ€ ์ •๋ณด๋ฅผ ๋ณต์‚ฌํ•ด์•ผ ํ•˜๋Š”๋ฐ, ๊ฐ€์žฅ ์‰ฌ์šด ๋ฐฉ๋ฒ•์€ elements ๋ฐฐ์—ด์˜ clone์„ ์žฌ๊ท€์ ์œผ๋กœ ํ˜ธ์ถœํ•ด ์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

์ด ๋ชจ๋“  ์ž‘์—…์ด ๊ผญ ํ•„์š” ํ• ๊นŒ... -> ๋ณต์‚ฌ ์ƒ์„ฑ์ž์™€ ๋ณต์‚ฌ ํŒฉํ„ฐ๋ฆฌ

// ๋ณต์‚ฌ ์ƒ์„ฑ์ž
public Yum(Yum yum) { ... };

// ๋ณต์‚ฌ ํŒฉํ„ฐ๋ฆฌ
public static Yum newInstance(Yum yum) { ... };
  • ๋‹คํ–‰ํžˆ๋„ ์ด์ฒ˜๋Ÿผ ๋ณต์žกํ•œ ๊ฒฝ์šฐ๋Š” ๋“œ๋ฌผ๋‹ค. Cloneable์„ ์ด๋ฏธ ๊ตฌํ˜„ํ•œ ํด๋ž˜์Šค๋ฅผ ํ™•์žฅํ•œ๋‹ค๋ฉด ์–ด์ฉ” ์ˆ˜ ์—†์ด clone์„ ์ž˜ ์ž‘๋™ํ•˜๋„๋ก ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์€ ์ƒํ™ฉ์—์„œ๋Š” ๋ณต์‚ฌ ์ƒ์„ฑ์ž์™€ ๋ณต์‚ฌ ํŒฉํ„ฐ๋ฆฌ๋ผ๋Š” ๋” ๋‚˜์€ ๊ฐ์ฒด ๋ณต์‚ฌ ๋ฐฉ์‹์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ•ต์‹ฌ์ •๋ฆฌ

Cloneable์ด ๋ชฐ๊ณ  ์˜จ ๋ชจ๋“  ๋ฌธ์ œ๋ฅผ ๋˜์งš์–ด๋ดค์„ ๋•Œ, ์ƒˆ๋กœ์šด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋งŒ๋“ค ๋•Œ๋Š” ์ ˆ๋Œ€ Cloneable์„ ํ™•์žฅํ•ด์„œ๋Š” ์•ˆ ๋˜๋ฉฐ, ์ƒˆ๋กœ์šด ํด๋ž˜์Šค๋„ ์ด๋ฅผ ๊ตฌํ˜„ํ•ด์„œ๋Š” ์•ˆ ๋œ๋‹ค. final ํด๋ž˜์Šค๋ผ๋ฉด Cloneable์„ ๊ตฌํ˜„ํ•ด๋„ ์œ„ํ—˜์ด ํฌ์ง€ ์•Š์ง€๋งŒ, ์„ฑ๋Šฅ ์ตœ์ ํ™” ๊ด€์ ์—์„œ ๊ฒ€ํ† ํ•œ ํ›„ ๋ณ„๋‹ค๋ฅธ ๋ฌธ์ œ๊ฐ€ ์—†์„ ๋•Œ๋งŒ ๋“œ๋ฌผ๊ฒŒ ํ—ˆ์šฉํ•ด์•ผ ํ•œ๋‹ค. ๊ธฐ๋ณธ ์›์น™์€ ๋ณต์ œ ๊ธฐ๋Šฅ์€ ์ƒ์„ฑ์ž์™€ ํŒฉํ„ฐ๋ฆฌ๋ฅผ ์ด์šฉํ•˜๋Š” ๊ฒŒ ์ตœ๊ณ ๋ผ๋Š” ๊ฒƒ์ด๋‹ค. ๋‹จ, ๋ฐฐ์—ด๋งŒ์€ clone ๋ฉ”์„œ๋“œ ๋ฐฉ์‹์ด ๊ฐ€์žฅ ๊น”๋”ํ•œ, ์ด ๊ทœ์น™์˜ ํ•ฉ๋‹นํ•œ ์˜ˆ์™ธ๋ผ ํ•  ์ˆ˜ ์žˆ๋‹ค.

โš ๏ธ **GitHub.com Fallback** โš ๏ธ