[์ดํŽ™ํ‹ฐ๋ธŒ ์ž๋ฐ”] Item13. clone ์žฌ์ •์˜๋Š” ์ฃผ์˜ํ•ด์„œ ์ง„ํ–‰ํ•˜๋ผ. (๊ฐ€๋ณ€ ๊ฐ์ฒด clone ์ •์˜ํ•˜๋Š” ๋ฐฉ๋ฒ•)

2023. 2. 1. 17:04ใ†JAVA/Effective JAVA

728x90

 

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

 

 

https://hyejin.tistory.com/1039

 

[์ดํŽ™ํ‹ฐ๋ธŒ ์ž๋ฐ”] Item13. clone ์žฌ์ •์˜๋Š” ์ฃผ์˜ํ•ด์„œ ์ง„ํ–‰ํ•˜๋ผ. (Clone๊ทœ์•ฝ)

item13. clone ์žฌ์ •์˜๋Š” ์ฃผ์˜ํ•ด์„œ ์ง„ํ–‰ํ•˜๋ผ. Clone() ์ด๋ž€? : Object ํด๋ž˜์Šค์˜ clone() ๋ฉ”์„œ๋“œ๋Š” ์ž์‹ ์„ ๋ณต์ œํ•˜์—ฌ ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์ผ์„ ํ•œ๋‹ค. ๋‹จ์ˆœํžˆ ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜์˜ ๊ฐ’๋งŒ ๋ณต์‚ฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ฐธ

hyejin.tistory.com

-> ์œ„์˜ ๊ฒŒ์‹œ๊ธ€์˜ ์˜ˆ์‹œ์ฒ˜๋Ÿผ ๋ถˆ๋ณ€ ํด๋ž˜์Šค๋Š” Cloneable ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ , clone()์„ ์žฌ์ •์˜ํ•ด์ฃผ๋ฉด ๋˜๋Š”๋ฐ 

clone()์€ ๋‹จ์ˆœํžˆ ๊ฐ์ฒด์— ์ €์žฅ๋œ ๊ฐ’์„ ๊ทธ๋Œ€๋กœ ๋ณต์‚ฌํ•  ๋ฟ, ๊ฐ์ฒด๊ฐ€ ์ฐธ์กฐํ•˜๊ณ  ์žˆ๋Š” ๊ฐ์ฒด๊นŒ์ง€ ๋ณต์‚ฌํ•˜์ง€๋Š” ์•Š๊ธฐ ๋•Œ๋ฌธ์—

๊ฐ€๋ณ€ ๊ฐ์ฒด์˜ ๊ฒฝ์šฐ์—๋Š” ์ฃผ์˜ํ•  ์ ์ด ์žˆ๋‹ค. 

 

 

shallow copy ์–•์€ ๋ณต์‚ฌ 

: ์›๋ณธ๊ณผ ๋ณต์‚ฌ๋ณธ์ด ๊ฐ™์€ ๊ฐ์ฒด๋ฅผ ๊ณต์œ ํ•œ๋‹ค. -> ์›๋ณธ์„ ๋ณ€๊ฒฝํ•˜๋ฉด ๋ณต์‚ฌ๋ณธ์—๋„ ์˜ํ–ฅ์„ ๋ฐ›๋Š”๋‹ค. 

package chapter02.item13;

import java.security.Signature;
import java.util.Arrays;
import java.util.EmptyStackException;

/**
 * item13. clone ์žฌ์ •์˜๋Š” ์ฃผ์˜ํ•ด์„œ ์ง„ํ–‰ํ•˜๋ผ.
 * ๊ฐ€๋ณ€ ๊ฐ์ฒด clone ์ •์˜ํ•˜๋Š” ๋ฐฉ๋ฒ• - shallow copy
 */
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];
    }

    public void push(Object o) {
        ensureCapacity();
        elements[size++] = o;
    }

    public Object pop() {
        if (size == 0) {
            throw new EmptyStackException();
        }

        Object result = elements[--size];
        elements[size] = null; // ๋‹ค ์“ด ์ฐธ์กฐ ํ•ด์ œ
        return result;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public Stack clone()  {
        try {
            Stack result = (Stack) super.clone();
            return result;
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }

    // ์›์†Œ๋ฅผ ์œ„ํ•œ ๊ณต๊ฐ„์„ ์ ์–ด๋„ ํ•˜๋‚˜ ์ด์ƒ ํ™•๋ณดํ•œ๋‹ค.
    private void ensureCapacity() {
        if (elements.length == size) {
            elements = Arrays.copyOf(elements, 2 * size + 1);
        }
    }

    public static void main(String[] args) {
        Object[] values = new Object[2];
        values[0] = new PhoneNumber(123, 456, 7890);
        values[1] = new PhoneNumber(321, 765, 4321);

        Stack stack = new Stack();
        for (Object arg : values) {
            stack.push(arg);
        }

        Stack copy = stack.clone();

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

        System.out.println("pop from copy");
        while (!copy.isEmpty()) {
            System.out.println(copy.pop() + " ");
        }

        System.out.println();
        System.out.println("stack.elements[0] == copy.elements[0] = " + (stack.elements[0] == copy.elements[0]));
    }
}

๋งŒ์•ฝ clone() ์„ ์œ„์™€ ๊ฐ™์ด ํ•œ๋‹คํ•˜๋ฉด ์›๋ณธ๊ณผ ๋ณต์‚ฌ๋ณธ์ด ๊ฐ™์€ elements๋ฅผ ๊ณต์œ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— 

-> ์ด๋ฏธ stack์—์„œ ๊ฐ’์„ ๋‹ค ๊บผ๋ƒˆ๊ธฐ ๋•Œ๋ฌธ์— copy์—์„œ๋Š” ๊บผ๋‚ผ ๊ฐ’์ด ์—†์–ด์„œ Null์ด ๋‚˜์˜ค๋ฉฐ stack์˜ elements์™€ copy์˜ elements ๋ฅผ ๋น„๊ตํ•  ๋•Œ true๊ฐ€ ๋ฐ˜ํ™˜๋˜๋Š” ๊ฒƒ๋„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

@Override
public Stack clone()  {
    try {
        Stack result = (Stack) super.clone();
        // elements.clone()์„ ํ•˜์ง€์•Š์œผ๋ฉด stack๊ณผ copy๊ฐ€ ๋™์ผํ•œ ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•˜๊ฒŒ ๋œ๋‹ค!!
        // ๊ทผ๋ฐ ๋ฐฐ์—ด์€ ์—ฌ์ „ํžˆ ๋™์ผํ•œ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ณด๊ณ  ์žˆ๋‹ค.
        // stack -> elementS[0, 1]
        // copy -> elementC[0,1]
        // elementS[0] == elementC[0]
        result.elements = elements.clone();
        return result;
    } catch (CloneNotSupportedException e) {
        throw new RuntimeException(e);
    }
}

๊ทธ๋Ÿผ clone์„ ์œ„์™€ ๊ฐ™์ด ์žฌ์ •์˜ํ•ด์ค€๋‹ค๊ณ  ํ•˜๋ฉด 

copy์—๋„ elements ๋ฅผ ๋ณต์‚ฌํ•ด์„œ ๊บผ๋‚ผ ์ˆ˜ ์žˆ์ง€๋งŒ, stack.elements ์™€ ๊ฐ์ฒด ๋น„๊ต๋ฅผ ๋ณด๋ฉด true๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค..!! 

์ด๋Ÿฐ ๊ฒฝ์šฐ์—๋Š” deep copy ๊ฐ€ ํ•„์š”ํ•˜๋‹ค. 

 

 

deep copy  ๊นŠ์€ ๋ณต์‚ฌ 

: ์›๋ณธ์ด ์ฐธ์กฐํ•˜๊ณ  ์žˆ๋Š” ๊ฐ์ฒด๊นŒ์ง€ ๋ณต์‚ฌํ•˜์—ฌ ์›๋ณธ์„ ๋ณ€๊ฒฝํ•˜๋”๋ผ๋„ ๋ณต์‚ฌ๋ณธ์— ์˜ํ–ฅ์ด ์—†๊ฒŒ ํ•˜๋Š” ๋ณต์‚ฌ์ด๋‹ค. 

package chapter02.item13;

/**
 * item13. clone ์žฌ์ •์˜๋Š” ์ฃผ์˜ํ•ด์„œ ์ง„ํ–‰ํ•˜๋ผ.
 * ๊ฐ€๋ณ€ ๊ฐ์ฒด clone ์ •์˜ํ•˜๋Š” ๋ฐฉ๋ฒ• - deep copy
 */
public class HashTable implements Cloneable {

    private Entry[] buckets = new Entry[10];

    private static class Entry {
        final Object key;
        Object value;
        Entry next;

        public Entry(Object key, Object value, Entry next) {
            this.key = key;
            this.value = value;
            this.next = next;
        }

        public void add(Object key, Object value) {
            this.next = new Entry(key, value, null);
        }

        // ์žฌ๊ท€์ ์ธ ๋ฐฉ๋ฒ•์€ StackOverflow๋ฅผ ๋ฐœ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—..
        public Entry deepCopy() {
            return new Entry(key, value, next == null ? null : next.deepCopy());
        }


    }



    // deep copy clone
    @Override
    public HashTable clone() {
        HashTable result = null;
        try {
            result = (HashTable) super.clone();
            result.buckets = new Entry[this.buckets.length]; // clone ์šฉ ๋ฐฐ์—ด ์ƒˆ๋กœ ๋งŒ๋“ค์–ด์คŒ

            for (int i = 0; i < this.buckets.length; i++) {
                if (buckets[i] != null) {
                    result.buckets[i] = this.buckets[i].deepCopy();
                }
            }
            return result;

        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }

    public static void main(String[] args) {
        HashTable hashTable = new HashTable();
        Entry entry = new Entry(new Object(), new Object(), null);
        hashTable.buckets[0] = entry;

        HashTable clone = hashTable.clone();
        System.out.println("(hashTable.buckets[0] == entry) = " + (hashTable.buckets[0] == entry));
        System.out.println("hashTable.buckets[0] == clone.buckets[0] = " + (hashTable.buckets[0] == clone.buckets[0]));
    }
}

depp copy ๋ฉ”์„œ๋“œ๋ฅผ ๋งŒ๋“ค์–ด์ฃผ๊ณ , clone ํ•  ๋•Œ clone์šฉ ๋ฐฐ์—ด์„ ์ƒˆ๋กœ ๋งŒ๋“ค์–ด์ฃผ๊ณ  ๊ทธ ๋ฐฐ์—ด์— ๊ฐ’์„ ๋„ฃ์–ด์ค€๋‹ค. 

๊ทผ๋ฐ ์ด๋•Œ ์œ„์—์„œ ๋งŒ๋“  deep copy๋Š” ์žฌ๊ท€ํ•จ์ˆ˜๋ผ ๋ฐฐ์—ด์˜ ํฌ๊ธฐ๋งŒํผ ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ํฌ๊ธฐ๊ฐ€ ํฐ ๋ฐฐ์—ด์ด๋ผ๋ฉด stackOverflow๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— 

์žฌ๊ท€ํ•จ์ˆ˜๋ณด๋‹ค๋Š” ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. 

 

public Entry deepCopy() {
    Entry result = new Entry(key, value, next);
    for (Entry p = result; p.next != null; p = p.next) {
        p.next = new Entry(p.next.key, p.next.value, p.next.next);
    }

    return result;
}

์ด๋ ‡๊ฒŒ ๊ตฌํ˜„ํ•œ ํ›„์— main ๋ฉ”์„œ๋“œ๋ฅผ ๋Œ๋ ค๋ณด๋ฉด 

์ด์ œ ๋ฐฐ์—ด์˜ ๊ฐ’๋„ ๋‹ค๋ฅธ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

 

 

 

 

 

 

 

 

 

 

728x90