ITEM 13: overriding clone judiciously

public interface Cloneable {
}

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

์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค๋Š” ๊ฒƒ์€ ์ผ๋ฐ˜์ ์œผ๋กœ ํ•ด๋‹น ํด๋ž˜์Šค๊ฐ€ ๊ทธ ์ธํ„ฐํŽ˜์ด์Šค์—์„œ ์ •์˜ํ•œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค๊ณ  ์„ ์–ธํ•˜๋Š” ํ–‰์œ„์ธ๋ฐ, Cloneable์˜ ๊ฒฝ์šฐ์—๋Š” ์ƒ์œ„ ํด๋ž˜์Šค์— ์ •์˜๋œ ๋™์ž‘ ๋ฐฉ์‹์„ ๋ณ€๊ฒฝํ•œ ๊ฒƒ์ด๋ฏ€๋กœ ๋”ฐ๋ผํ•˜๋Š” ๊ฒƒ์€ ์ข‹์ง€ ์•Š๋‹ค.

๋ถˆ๋ณ€ ํด๋ž˜์Šค๋Š” ๊ตณ์ด clone์„ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

public final class PhoneNumber implements Cloneable{
    private final short areaCode, prefix, lineNum;
    private int hashCode;

    @Override
    public PhoneNumber clone(){
        try{
            // ํ˜•๋ณ€ํ™˜
            return (PhoneNumber) super.clone();
        }catch (CloneNotSupportedException e){
            throw new AssertionError();
        }
    }
}
public class Object {

    @HotSpotIntrinsicCandidate
    protected native Object clone() throws CloneNotSupportedException;

try-catch๋กœ ๊ตฌํ˜„ํ•œ ์ด์œ ๋Š” Object์˜ clone()์ด CloneNotSupportedException์„ ๋˜์ ธ์ฃผ๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋ฉฐ, Cloneable์„ ๊ตฌํ˜„ํ•˜๋ฉด CloneNotSupportedException์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์„ ๊ฒƒ์„ ์•ˆ๋‹ค.

Object ๋ฉ”์„œ๋“œ๋Š” CloneNotSupportedException์„ ๋˜์ง„๋‹ค๊ณ  ์„ ์–ธํ–ˆ์ง€๋งŒ, ์žฌ์ •์˜ํ•œ ๋ฉ”์†Œ๋“œ์—์„œ๋Š” throws์ ˆ์„ ์—†์• ๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ๊ฒ€์‚ฌ ์˜ˆ์™ธ๋ฅผ ๋˜์ง€์ง€ ์•Š์•„์•ผ ๊ทธ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ํŽธํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.(๋น„๊ฒ€์‚ฌ ์˜ˆ์™ธ-item71)

clone()์€ ์›๋ณธ ๊ฐ์ฒด์— ์•„๋ฌด๋Ÿฐ ํ•ด๋ฅผ ๋ผ์น˜์ง€ ์•Š๋Š” ๋™์‹œ์— ๋ณต์ œ๋œ ๊ฐ์ฒด์˜ ๋ถˆ๋ณ€์‹์„ ๋ณด์žฅํ•ด์•ผํ•œ๋‹ค.

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

    public Stack() {
        elements = new Object[DEFAULT_CAPACITY];
    }

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

    public Object pop(){
        if(size == 0){
            throw new EmptyStackException();
        }
        return elements[--size];
    }

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

}

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

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

์›๋ณธ ๊ฐ์ฒด๋ฅผ ์œ ์ง€ํ•˜๋ฉด์„œ ๋ณต์ œ๋œ ๊ฐ์ฒด์˜ ๋ถˆ๋ณ€์„ ์œ ์ง€ํ•˜๋Š” ๊ฐ€์žฅ ์‰ฌ์šด ๋ฐฉ๋ฒ•์€ elements ๋ฐฐ์—ด์˜ clone์„ ์žฌ๊ท€์ ์œผ๋กœ ํ˜ธ์ถœํ•ด์ฃผ๋Š” ๊ฒƒ์ด๋‹ค .์ด๋•Œ, ๋ฐฐ์—ด์˜ clone์€ ๋Ÿฐํƒ€์ž„ ํƒ€์ž…๊ณผ ์ปดํŒŒ์ผํƒ€์ž„ ํƒ€์ž… ๋ชจ๋‘๊ฐ€ ์›๋ณธ ๋ฐฐ์—ด๊ณผ ๋˜‘๊ฐ™์€ ๋ฐฐ์—ด์„ ๋ฐ˜ํ™˜ํ•˜๋ฏ€๋กœ ๋ณ„๋„๋กœ ํ˜•๋ณ€ํ™˜์„ ํ•ด์ค„ ํ•„์š”๋Š” ์—†๋‹ค. ๋”ฐ๋ผ์„œ ๋ฐฐ์—ด์„ ๋ณต์ œํ•  ๋•Œ๋Š” ๋ฐฐ์—ด์˜ clone ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•œ๋‹ค.

ํ•œํŽธ ์œ„ Stack ํด๋ž˜์Šค์˜ elements ํ•„๋“œ๊ฐ€ final์ด์—ˆ๋‹ค๋ฉด final ํ•„๋“œ๋Š” ์ƒˆ๋กœ์šด ๊ฐ’์„ ํ• ๋‹นํ•  ์ˆ˜ ์—†๊ธฐ๋•Œ๋ฌธ์— ์œ„ clone() ๋ฉ”์„œ๋“œ ๋ฐฉ์‹์€ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค.

Cloneable ์•„ํ‚คํ…์ฒ˜๋Š” ๊ฐ€๋ณ€ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•˜๋Š” ํ•„๋“œ๋Š” final๋กœ ์„ ์–ธํ•˜๋ผ๋Š” ์ผ๋ฐ˜ ์šฉ๋ฒ•๊ณผ ์ถฉ๋Œํ•œ๋‹ค. ์›๋ณธ๊ณผ ๋ณต์ œ๋œ ๊ฐ์ฒด๊ฐ€ ๊ฐ€๋ณ€ ๊ฐ์ฒด๋ฅผ ๊ณต์œ ํ•ด๋„ ๋œ๋‹ค๋ฉด ์ƒ๊ด€์—†์ง€๋งŒ, ๋ณต์ œํ•  ์ˆ˜ ์žˆ๋Š” ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์ผ๋ถ€ ํ•„๋“œ์—์„œ final ํ•œ์ •์ž๋ฅผ ์ œ๊ฑฐํ•ด์•ผํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

public class HashTable implements Cloneable{
    private Entry[] buckets = new Entry[10];

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

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


        Entry deepCopy(){
            // ํ•ด๋‹น ์—”ํŠธ๋ฆฌ๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋ฅผ ์žฌ๊ท€์ ์œผ๋กœ ๋ณต์‚ฌ
            // ์žฌ๊ท€ ํ˜ธ์ถœ์ด๊ธฐ ๋•Œ๋ฌธ์—, ๋ฆฌ์ŠคํŠธ์˜ ์›์†Œ ์ˆ˜ ๋งŒํผ ์Šคํƒ ํ”„๋ ˆ์ž„์„ ์†Œ๋น„ํ•ด ๋ฆฌ์ŠคํŠธ๊ฐ€ ๊ธธ๋ฉด ์Šคํƒ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ ๋ฐœ์ƒ ์œ„ํ—˜ ์žˆ์Œ.
            // return new Entry(key, value, next == null ? null : next.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;
        }
    }

    /**
     * ์ž˜๋ชป๋œ Clone
     * ์›๋ณธ๊ณผ ๊ฐ™์€ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ฐธ์กฐ ํ•ด ์›๋ณธ๊ณผ ๋ณต์ œ๋ณธ ๋ชจ๋‘ ์˜ˆ๊ธฐ์น˜ ์•Š๊ฒŒ ๋™์ž‘ํ•  ๊ฐ€๋Šฅ์„ฑ ์ƒ๊น€
     * @return
     * @Override
     *     public  HashTable clone(){
     *         try{
     *             HashTable result = (HashTable) super.clone();
     *             result.buckets = buckets.clone();
     *             return result;
     *         }catch (CloneNotSupportedException e){
     *             throw new AssertionError();
     *         }
     *     }
     */


    /**
     *
     * @return
     */
    @Override
    public  HashTable clone(){
        try{
            HashTable result = (HashTable) super.clone();
            result.buckets = new Entry[buckets.length];
            for(int i =0 ; i < buckets.length; i++){
                if(buckets[i] != null){
                    result.buckets[i] = buckets[i].deepCopy();
                }
            }
            return result;
        }catch (CloneNotSupportedException e){
            throw new AssertionError();
        }
    }
}

HashTable ํด๋ž˜์Šค๋ฅผ ๋ณด๋ฉด, Stack๊ณผ ๋™์ผํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ clone()์„ ๊ตฌํ˜„ํ•˜๋ฉด ์›๋ณธ๊ณผ ๊ฐ™์€ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ฐธ์กฐ ํ•ด ์›๋ณธ๊ณผ ๋ณต์ œ๋ณธ ๋ชจ๋‘ ์˜ˆ๊ธฐ์น˜ ์•Š๊ฒŒ ๋™์ž‘ํ•  ๊ฐ€๋Šฅ์„ฑ ์ƒ๊ธธ ์ˆ˜ ์žˆ๊ธฐ๋•Œ๋ฌธ์—, deepCopy()๋ฅผ ๋ณ„๋„๋กœ ๊ตฌํ˜„ํ•˜์—ฌ ํ•ด๋‹น ์—”ํŠธ๋ฆฌ๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋ฅผ ์žฌ๊ท€์ ์œผ๋กœ ๋ณต์‚ฌํ•ด์ฃผ์—ˆ๋‹ค.

clone() ๋ฉ”์„œ๋“œ๋Š” ์žฌ์ •์˜๋  ์ˆ˜ ์žˆ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด์„œ๋Š” ์•ˆ๋œ๋‹ค. ๋งŒ์•ฝ clone()์ด ํ•˜์œ„ ํด๋ž˜์Šค์—์„œ ์žฌ์ •์˜ํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด, ํ•˜์œ„ ํด๋ž˜์Šค๋Š” ๋ณต์ œ ๊ณผ์ •์—์„œ ์ž์‹ ์˜ ์ƒํƒœ๋ฅผ ๊ต์ •ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐํšŒ๋ฅผ ์ผ๊ฒŒ๋˜์–ด ์›๋ณธ๊ณผ ์ƒํƒœ๊ฐ€ ๋‹ฌ๋ผ์งˆ ๊ฐ€๋Šฅ์„ฑ์ด ์ปค์ง€๊ฒŒ๋œ๋‹ค.

์š”์•ฝํ•˜์ž๋ฉด, Cloneable์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ชจ๋“  ํด๋ž˜์Šค๋Š” clone()์„ ์žฌ์ •์˜ํ•ด์•ผ ํ•œ๋‹ค. ์ด๋•Œ ์ ‘๊ทผ ์ œํ•œ์ž๋Š” public์œผ๋กœ, ๋ฐ˜ํ™˜ ํƒ€์ž…์€ ํด๋ž˜์Šค ์ž์‹ ์œผ๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค. ๊ฐ€์žฅ ๋จผ์ € super.clone ์„ ํ˜ธ์ถœํ•œ ํ›„ ํ•„์š”ํ•œ ํ•„๋“œ๋ฅผ ์ „๋ถ€ ์ ์ ˆํžˆ ์ˆ˜์ •ํ•ด์ค˜์•ผ ํ•œ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ '๊นŠ์€ ๊ตฌ์กฐ'์— ์ˆจ์–ด ์žˆ๋Š” ๋ชจ๋“  ๊ฐ€๋ณ€ ๊ฐ์ฒด๋ฅผ ๋ณต์‚ฌํ•˜๊ณ , ๋ณต์ œ๋ณธ์ด ๊ฐ€์ง„ ๊ฐ์ฒด ์ฐธ์กฐ ๋ชจ๋‘๊ฐ€ ๋ณต์‚ฌ๋œ ๊ฐ์ฒด๋“ค์„ ๊ฐ€๋ฆฌํ‚ค๊ฒŒ ํ•ด์•ผํ•œ๋‹ค. ๊ธฐ๋ณธ ํƒ€์ž… ํ•„๋“œ์™€ ๋ถˆ๋ณ€ ๊ฐ์ฒด ์ฐธ์กฐ๋งŒ์„ ๊ฐ–๋Š” ํด๋ž˜์Šค๋ผ๋ฉด ์•„๋ฌด ํ•„๋“œ๋„ ์ˆ˜์ •ํ•  ํ•„์š”๋Š” ์—†๋‹ค.

Cloneable์„ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์€ ํด๋ž˜์Šค๋ผ๋ฉด ๋ณต์‚ฌ ์ƒ์„ฑ์ž์™€ ๋ณต์‚ฌ ํŒฉํ„ฐ๋ฆฌ๋ผ๋Š” ๋” ๋‚˜์€ ๊ฐ์ฒด ๋ณต์‚ฌ ๋ฐฉ์‹์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋‹ค.

// ๋ณต์‚ฌ์ƒ์„ฑ์ž
public Item(Item item){...};
// ๋ณต์‚ฌ ํŒฉํ„ฐ๋ฆฌ
public static Item newInstance(Item item){...};

๋ณต์‚ฌ ์ƒ์„ฑ์ž๋ž€ ๋‹จ์ˆœํžˆ ์ž์‹ ๊ณผ ๊ฐ™์€ ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ธ์ˆ˜๋กœ ๋ฐ›๋Š” ์ƒ์„ฑ์ž๋ฅผ ๋งํ•œ๋‹ค.

๋ณต์‚ฌ ์ƒ์„ฑ์ž/ํŒฉํ„ฐ๋ฆฌ๋Š”

  • ์ƒ์„ฑ์ž๋ฅผ ์“ฐ์ง€ ์•Š๋Š” ๋ฐฉ์‹์˜ ๊ฐ์ฒด ์ƒ์„ฑ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.

  • ์—‰์„ฑํ•˜๊ฒŒ ๋ฌธ์„œํ™”๋œ ๊ทœ์•ฝ์— ๊ธฐ๋Œ€์ง€ ์•Š๊ณ , ์ •์ƒ์ ์ธ final ํ•„๋“œ ์šฉ๋ฒ•๊ณผ๋„ ์ถฉ๋Œํ•˜์ง€ ์•Š๋Š”๋‹ค.

  • ๋ถˆํ•„์š”ํ•œ ๊ฒ€์‚ฌ ์˜ˆ์™ธ๋ฅผ ๋˜์ง€์ง€ ์•Š๊ณ , ํ˜•๋ณ€ํ™˜๋„ ํ•„์š”์น˜ ์•Š๋Š”๋‹ค.

  • ํ•ด๋‹น ํด๋ž˜์Šค๊ฐ€ ๊ตฌํ˜„ํ•œ ์ธํ„ฐํŽ˜์ด์Šค ํƒ€์ž…์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ธ์ˆ˜๋กœ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.

๋ชจ๋“  ๋ฒ”์šฉ ์ปฌ๋ ‰์…˜ ๊ตฌํ˜„์ฒด๋Š” Collection ์ด๋‚˜ Map ํƒ€์ž…์„ ๋ฐ›๋Š” ์ƒ์„ฑ์ž๋ฅผ ์ œ๊ณตํ•œ๋‹ค. ์ด๋ฅผ ์ด์šฉํ•˜๋ฉด ํด๋ผ์ด์–ธํŠธ๋Š” ์›๋ณธ์˜ ๊ตฌํ˜„ ํƒ€์ž…์— ์–ฝ๋งค์ด์ง€ ์•Š๊ณ  ๋ณต์ œ๋ณธ์˜ ํƒ€์ž…์„ ์ง์ ‘ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋‹ค. (HashSet์„ TreeSet ํƒ€์ž…์œผ๋กœ ๋ณต์ œ ๊ฐ€๋Šฅ)

new TreeSet<>(s);

Last updated