Item 13. clone

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

Cloneable

public interface Cloneable {
    // ์–ด๋–ค ๊ตฌํ˜„๋„ ๋˜์–ด ์žˆ์ง€ ์•Š์Œ
}

Cloneable์€ ๋ณต์ œํ•ด๋„ ๋˜๋Š” ํด๋ž˜์Šค์ž„์„ ๋ช…์‹œํ•˜๊ธฐ ์œ„ํ•œ ์ธํ„ฐํŽ˜์ด์Šค์ด๋‹ค. ํ•˜์ง€๋งŒ ์˜๋„์™€๋Š” ๋‹ค๋ฅด๊ฒŒ ํ•ด๋‹น ๋ชฉ์ ์„ ์ œ๋Œ€๋กœ ์ˆ˜ํ–‰ํ•˜์ง€ ๋ชปํ•˜๊ณ  ์žˆ๋Š”๋ฐ, ๊ทธ ์ด์œ ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • clone ๋ฉ”์„œ๋“œ๊ฐ€ ์„ ์–ธ๋œ ๊ณณ์ด Cloneable์ด ์•„๋‹Œ Object์— protected๋กœ ์„ ์–ธ๋˜์–ด ์žˆ์Œ

  • ๋•Œ๋ฌธ์— ๋น„์–ด์žˆ๋Š” Cloneable์„ ๊ตฌํ˜„ํ•ด๋„ clone ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†์Œ

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

Cloneable ์ธํ„ฐํŽ˜์ด์Šค์˜ ์—ญํ• 

๋‚ด๋ถ€ ๊ตฌํ˜„์ด ์•„๋ฌด๊ฒƒ๋„ ์—†์ง€๋งŒ Object์˜ protected ๋ฉ”์„œ๋“œ์ธ clone์˜ ๋™์ž‘ ๋ฐฉ์‹์„ ๊ฒฐ์ •ํ•œ๋‹ค. Cloneable์„ ๊ตฌํ˜„ํ•œ ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค์—์„œ clone ํ˜ธ์ถœํ•˜๋ฉด ํ•ด๋‹น ๊ฐ์ฒด์˜ ํ•„๋“œ๋“ค์„ ํ•˜๋‚˜ํ•˜๋‚˜ ๋ณต์‚ฌํ•œ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ , Cloneable์„ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์€ ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค์—์„œ clone ํ˜ธ์ถœํ•˜๋ฉด CloneNotSupportedException์„ ๋˜์ง„๋‹ค.

class NotCloneable {
    int x;
    int y;

    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

class Cloneable implements java.lang.Cloneable {
    int x;
    int y;

    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

class Main {
    public static void main(String[] args) throws CloneNotSupportedException {
        Cloneable cloneable = new Cloneable();
        NotCloneable notCloneable = new NotCloneable();

        cloneable.clone(); // OK
        notCloneable.clone(); // CloneNotSupportedException
    }
}

์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ƒ๋‹นํžˆ ์ด๋ก€์ ์œผ๋กœ ์‚ฌ์šฉํ•œ ์‚ฌ๋ก€๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค๋ฅธ ๊ณณ์— ์ด๋Ÿฌํ•œ ๋ฐฉ์‹์„ ์ ์šฉํ•˜๋Š” ๊ฒƒ์€ ์ข‹์ง€ ์•Š๋‹ค. (์ผ๋ฐ˜์ ์œผ๋กœ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์€ ํ•ด๋‹น ์ธํ„ฐํŽ˜์ด์Šค์—์„œ ์ •์˜ ํ•œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ด์ง€๋งŒ, ์ด ๊ฒฝ์šฐ์—” ์ƒ์œ„ ํด๋ž˜์Šค์— ์ •์˜๋œ ๋™์ž‘ ๋ฐฉ์‹์„ ๊ฒฐ์ •ํ•œ๋‹ค.)

Object.clone

clone ๋ฉ”์„œ๋“œ์˜ ๊ทœ์•ฝ์€ ํ—ˆ์ˆ ํ•œ ํŽธ์ธ๋ฐ, Object ๋ช…์„ธ์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ •๋ฆฌ๋˜์–ด ์žˆ๋‹ค.

  • ๊ฐ์ฒด์˜ ๋ณต์‚ฌ๋ณธ์„ ์ƒ์„ฑํ•ด ๋ฐ˜ํ™˜

    • ๋ณต์‚ฌ์˜ ์ •ํ™•ํ•œ ๋œป์€ ๊ทธ ๊ฐ์ฒด๋ฅผ ๊ตฌํ˜„ํ•œ ํด๋ž˜์Šค์— ๋”ฐ๋ผ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Œ

  • ์ผ๋ฐ˜์ ์ธ ์˜๋„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Œ(๋ฐ˜๋“œ์‹œ ์ด๋ ‡๊ฒŒ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹˜)

    • x.clone() != x

    • x.clone().getClass() == x.getClass()

    • x.clone().equals(x)

์˜ฌ๋ฐ”๋ฅธ Cloneable ๊ตฌํ˜„ ๋ฐฉ๋ฒ•

class Point implements Cloneable {
    private final int x;
    private final int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public Point clone() {
        try {
            return (Point) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError(); // ์ผ์–ด๋‚˜์ง€ ์•Š๋Š” ์—๋Ÿฌ, ์™ธ๋ถ€๋กœ ๋˜์ง€์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹์Œ
        }
    }
}

clone ๋ฉ”์„œ๋“œ๋ฅผ public์œผ๋กœ ์ œ๊ณตํ•˜๊ณ , super.clone์„ ํ˜ธ์ถœํ•œ ํ›„ ๋ฐ˜ํ™˜ ํƒ€์ž…์„ ํ•ด๋‹น ํด๋ž˜์Šค๋กœ ์บ์ŠคํŒ…ํ•˜๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ ์ธ ๋ฐฉ๋ฒ•์ด๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ธฐ๋ณธ ํƒ€์ž…์ด๊ฑฐ๋‚˜ ๋ถˆ๋ณ€ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•˜๋Š” ํ•„๋“œ์— ๋Œ€ํ•ด์„œ๋Š” ๋ฌธ์ œ๊ฐ€ ์—†์ง€๋งŒ, ๊ฐ€๋ณ€ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•˜๋Š” ํ•„๋“œ์— ๋Œ€ํ•ด์„œ๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

๊ฐ€๋ณ€ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•˜๋Š” ํ•„๋“œ๊ฐ€ ์žˆ๋Š” ํด๋ž˜์Šค์˜ clone

Stack ํด๋ž˜์Šค์ฒ˜๋Ÿผ ๊ฐ€๋ณ€ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•˜๋Š” ํ•„๋“œ๊ฐ€ ์žˆ๋Š” ํด๋ž˜์Šค๋ฅผ ์œ„ ๋ฐฉ์‹์ฒ˜๋Ÿผ ๊ทธ๋Œ€๋กœ ๋ณต์‚ฌ๋ฅผ ํ•˜๊ฒŒ ๋˜๋ฉด, ๋‚ด๋ถ€ ์›์†Œ๋“ค๊นŒ์ง€ ๊ฐ™์€ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•˜๊ฒŒ ๋œ๋‹ค.

public class Stack implements Cloneable {
    private Object[] elements; // ๊ฐ€๋ณ€ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•˜๋Š” ํ•„๋“œ, ๊ทธ๋Œ€๋กœ ๋ณต์‚ฌํ•˜๋ฉด ๋‚ด๋ถ€ ์›์†Œ๋“ค๊นŒ์ง€ ๊ฐ™์€ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•˜๊ฒŒ ๋จ
    private int size = 0;
    private static final int DEFAULT_INITIAL_CAPACITY = 16;

    public Stack() {
        this.elements = new Object[DEFAULT_INITIAL_CAPACITY];
    }

    // ...
}

๋•Œ๋ฌธ์— ๊ฐ€๋ณ€ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•˜๋Š” ํด๋ž˜์Šค๋ผ๋ฉด clone ๋ฉ”์„œ๋“œ๋ฅผ ์žฌ์ •์˜ํ•  ๋•Œ ํ•ด๋‹น ํ•„๋“œ๋“ค์„ ์ƒˆ๋กœ ๋ณต์‚ฌํ•ด์„œ ์ฐธ์กฐํ•˜๋„๋ก ํ•ด์•ผ ํ•œ๋‹ค.

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

    public Stack() {
        this.elements = new Object[DEFAULT_INITIAL_CAPACITY];
    }

    @Override
    public Stack clone() {
        try {
            Stack result = (Stack) super.clone();
            result.elements = elements.clone(); // ๊ฐ€๋ณ€ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•˜๋Š” ํ•„๋“œ๋ฅผ ์žฌ๊ท€์ ์œผ๋กœ ๋ณต์‚ฌ
            return result;
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }

    // ...
}

ํ•˜์ง€๋งŒ ์ด ๋ฐฉ๋ฒ•์—๋„ ๋ฌธ์ œ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ๋Š”๋ฐ, ๋งŒ์•ฝ elements๊ฐ€ final์ด๋ผ๋ฉด ์ƒˆ๋กœ์šด ๊ฐ’์„ ํ• ๋‹นํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋ฌธ๋ฒ• ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ๊ทธ๋ž˜์„œ ๋ณต์ œํ•  ์ˆ˜ ์žˆ๋Š” ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์ผ๋ถ€ ํ•„๋“œ์—์„œ final์„ ์ œ๊ฑฐํ•ด์•ผ ํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์ถ”๊ฐ€์ ์œผ๋กœ ๊ฐ€๋ณ€ ๊ฐ์ฒด ๋‚ด๋ถ€์— ๋˜ ๋‹ค๋ฅธ ๊ฐ€๋ณ€ ๊ฐ์ฒด๊ฐ€ ์กด์žฌํ•œ๋‹ค๋ฉด, ํ•ด๋‹น ๊ฐ์ฒด๋“ค๋„ ์žฌ๊ท€์ ์œผ๋กœ ๋ณต์‚ฌํ•ด์•ผ ํ•จ์„ ์žŠ์ง€ ๋ง์•„์•ผ ํ•œ๋‹ค.

๊ฒฐ๋ก 

clone ๋ฉ”์„œ๋“œ๋Š” ๋ณต์ œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•ด ๊ณ ์•ˆ๋œ ๊ฒƒ์ด์ง€๋งŒ ์–ธ์–ด ๋ชจ์ˆœ์ ์ด๊ณ , ์—‰์„ฑํ•˜๊ฒŒ ๋ฌธ์„œํ™”๋œ ๊ทœ์•ฝ, ์˜ˆ์™ธ ๋ฐœ์ƒ ๊ฐ€๋Šฅ์„ฑ ๋“ฑ ๋ฌธ์ œ๊ฐ€ ๋งŽ๋‹ค. ์ด๋ฏธ Cloneable์„ ๊ตฌํ˜„ํ•œ ํด๋ž˜์Šค๋ฅผ ํ™•์žฅํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ๋ฉด ๋ณต์ œ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„ , ๋ณต์‚ฌ ์ƒ์„ฑ์ž๋‚˜ ๋ณต์‚ฌ ํŒฉํ„ฐ๋ฆฌ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ์ข‹๋‹ค.

Last updated

Was this helpful?