-
๐์ํฉ
- Cloneable์ ๋ณต์ ํด๋ ๋๋ ํด๋์ค์์ ๋ช
์ํ๋ ์ฉ๋์ธ mixin ์ธํฐํ์ด์ค์ง๋ง, ์์ฝ๊ฒ๋ ์๋ํ ๋ชฉ์ ์ ์ ๋๋ก ์ด๋ฃจ์ง ๋ชปํ์
- clone ๋ฉ์๋๊ฐ ์ ์ธ๋ ๊ณณ์ด Cloneable์ด ์๋ Object์ด๊ณ , protected๋ก ์ ์ธ๋จ --> Cloneable์ ๊ตฌํํ๋ ๊ฒ๋ง์ผ๋ก๋ ์ธ๋ถ ๊ฐ์ฒด์์ clone ๋ฉ์๋๋ฅผ ํธ์ถํ ์ ์์
- ๋ฆฌํ๋ ์ ์ ์ฌ์ฉํ๋ฉด ๊ฐ๋ฅํ์ง๋ง, 100% ์ฑ๊ณตํ๋ ๊ฒ์ ์๋ --> ํด๋น ๊ฐ์ฒด๊ฐ ์ ๊ทผ์ด ํ์ฉ๋ clone ๋ฉ์๋๋ฅผ ์ ๊ณตํ๋ค๋ ๋ณด์ฅ์ด ์๊ธฐ ๋๋ฌธ์
- ํ์ง๋ง Cloneable ๋ฐฉ์์ ๋๋ฆฌ ์ฐ์ด๊ณ ์์ด ์ ์์๋๋ ๊ฒ์ด ์ข์
์ด๋ฒ ์์ดํ ์์ ๋ค๋ฃฐ ๋ด์ฉ
- clone ๋ฉ์๋๋ฅผ ์ ๋์ํ๊ฒ๋ ํด์ฃผ๋ ๊ตฌํ ๋ฐฉ๋ฒ
- ์ธ์ ์ฌ์ ์ํด์ ์ฌ์ฉํด์ผ ํ๋์ง, ๊ฐ๋ฅํ ๋ค๋ฅธ ์ ํ์ง๋ ๋ฌด์์ธ์ง
๐๋ฐฉ๋ฒ
<์ฌ์ ์ง์>
Cloneable ์ธํฐํ์ด์ค์ ์ญํ
- ํด๋น ์ธํฐํ์ด์ค์๋ ์๋ฌด๋ฐ ๋ฉ์๋๋ ์ ์๋์ด ์์ง ์์
- Object์ protected ๋ฉ์๋์ธ clone์ ๋์ ๋ฐฉ์์ ๊ฒฐ์ ํจ
- Cloneable์ ๊ตฌํํ ํด๋์ค์ ์ธ์คํด์ค์์ clone์ ํธ์ถํ๋ฉด ๊ทธ ๊ฐ์ฒด์ ํ๋๋ค์ ํ๋ํ๋ ๋ณต์ฌํ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๊ณ , ๊ทธ๋ ์ง ์์ ํด๋์ค์ ์ธ์คํด์ค์์ ํธ์ถํ๋ฉด CloneNotSupportedException์ ๋์ง
- Cloneable์ ๊ฒฝ์ฐ์๋ ์์ ํด๋์ค์ ์ ์๋ protected ๋ฉ์๋์ ๋์ ๋ฐฉ์์ ๋ณ๊ฒฝํ ๊ฒ์
- ์ด๋ ์ธํฐํ์ด์ค๋ฅผ ์ด๋ก์ ์ผ๋ก ์ฌ์ฉํ ์์ด๋ ๋ฐ๋ผ ํ์ง ๋ง์
clone ๋ฉ์๋์ ์ผ๋ฐ ๊ท์ฝ
<์ ๋๋ก ๋์ํ๊ฒ๋ ํ๋ ๊ตฌํ ๋ฐฉ๋ฒ>
1) ๊ฐ๋ณ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ์ง ์๋ ํด๋์ค
์ฝ๋ 13-1 ๊ฐ๋ณ ์ํ๋ฅผ ์ฐธ์กฐํ์ง ์๋ ํด๋์ค์ฉ clone ๋ฉ์๋
@Override public PhoneNumber clone() { try { return (PhoneNumber) super.clone(); } catch (CloneNotSupportedException e) { throw new AssertionError(); } }
- super.clone์ ํธ์ถํจ
- ์ด๋ฅผ ํตํด ์ป์ ๊ฐ์ฒด๋ ์๋ณธ์ ์๋ฒฝํ ๋ณต์ ๋ณธ์
- ํด๋์ค์ ์ ์๋ ๋ชจ๋ ํ๋๋ ์๋ณธ ํ๋์ ๋๊ฐ์ ๊ฐ์ ๊ฐ์
- ๋ชจ๋ ํ๋๊ฐ ๊ธฐ๋ณธ ํ์ ์ด๊ฑฐ๋ ๋ถ๋ณ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ๋ค๋ฉด ์ด ๊ฐ์ฒด๋ ์๋ฒฝํ ์ฐ๋ฆฌ๊ฐ ์ํ๋ ์ํ์
- ํด๋น ๋ฉ์๋๊ฐ ๋์ํ๊ฒ ํ๋ ค๋ฉด PhoneNumber ํด๋์ค ์ ์ธ์ Cloneable์ ๊ตฌํํด์ผ ํจ
2) ๊ฐ๋ณ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ๋ ํด๋์ค
์์ - Stack ํด๋์ค
public 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]; } ... }
- clone ๋ฉ์๋๊ฐ ๋จ์ํ super.clone์ ๊ฒฐ๊ณผ๋ฅผ ๊ทธ๋๋ก ๋ฐํํ๋ค๋ฉด?
- ๋ฐํ๋ Stack ์ธ์คํด์ค์ size ํ๋๋ ์ฌ๋ฐ๋ฅธ ๊ฐ์ ๊ฐ์ง์ง๋ง, elements ํ๋๋ ์๋ณธ Stack ์ธ์คํด์ค์ ๋๊ฐ์ ๋ฐฐ์ด์ ์ฐธ์กฐํจ
- ์๋ณธ์ด๋ ๋ณต์ ๋ณธ ์ค ํ๋๋ฅผ ์์ ํ๋ฉด ๋ค๋ฅธ ํ๋๋ ์์ ๋์ด ๋ถ๋ณ์์ ํด์นจ
- ๋ฐ๋ผ์ ํ๋ก๊ทธ๋จ์ด ์ด์ํ๊ฒ ๋์ํ๊ฑฐ๋ NullPointerException์ ๋์ง ๊ฒ์
- clone ๋ฉ์๋๋ ์ฌ์ค์ ์์ฑ์์ ๊ฐ์ ํจ๊ณผ๋ฅผ ๋
- ์ฆ, clone์ ์๋ณธ ๊ฐ์ฒด์ ์๋ฌด๋ฐ ํด๋ฅผ ๋ผ์น์ง ์๋ ๋์์ ๋ณต์ ๋ ๊ฐ์ฒด์ ๋ถ๋ณ์์ ๋ณด์ฅํด์ผ ํจ
- ๋ฐ๋ผ์ Stack์ clone ๋ฉ์๋๊ฐ ์ ๋๋ก ๋์ํ๋ ค๋ฉด ์คํ ๋ด๋ถ ์ ๋ณด๋ฅผ ๋ณต์ฌํด์ผ ํจ
a) ์ฐธ์กฐ ๊ฐ์ฒด์ ๋ด๋ถ ์ ๋ณด๊น์ง ๋ณต์ฌํ๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผํ ๊น?
์ฝ๋ 13-2 ๊ฐ๋ณ ์ํ๋ฅผ ์ฐธ์กฐํ๋ ํด๋์ค์ฉ clone ๋ฉ์๋
@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 ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ผ๊ณ ๊ถ์ฅํจ --> ๋ฐฐ์ด์ clone ๊ธฐ๋ฅ์ ์ ๋๋ก ์ฌ์ฉํ๋ ์ ์ผํ ์
- ์ ์ฉํ์ง ๋ชปํ๋ ๊ฒฝ์ฐ
- elements ํ๋๊ฐ final์ธ ๊ฒฝ์ฐ ์์ ๋ฐฉ์์ ๋์ํ์ง ์์ (final ํ๋์๋ ์๋ก์ด ๊ฐ์ ํ ๋นํ ์ ์๊ธฐ ๋๋ฌธ)
- ์ด๋ '๊ฐ๋ณ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ๋ ํ๋๋ final๋ก ์ ์ธํ๋ผ'๋ ์ผ๋ฐ ์ฉ๋ฒ๊ณผ ์ถฉ๋ํจ
- ๋ณต์ ๊ฐ๋ฅํ ํด๋์ค๋ฅผ ๋ง๋ค๊ธฐ ์ํด ์ผ๋ถ ํ๋์์ final ํ์ ์๋ฅผ ์ ๊ฑฐํด์ผ ํ ์๋ ์์
b) clone์ ์ฌ๊ท์ ์ผ๋ก ํธ์ถํ๋ ๊ฒ๋ง์ผ๋ก ์ถฉ๋ถํ์ง ์์ ๊ฒฝ์ฐ๋ ์ด๋ป๊ฒ ํด์ผํ ๊น?
์์ - HashTable
- ํด์ํ ์ด๋ธ ๋ด๋ถ๋ ๋ฒํท๋ค์ ๋ฐฐ์ด์ด๊ณ , ๊ฐ ๋ฒํท์ ํค-๊ฐ ์์ ๋ด๋ ์ฐ๊ฒฐ๋ฆฌ์คํธ์ ์ฒซ ๋ฒ์งธ ์ํธ๋ฆฌ๋ฅผ ์ฐธ์กฐํจ
public class HashTable implements Cloneable { private Entry[] buckets = ...; 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; } } ... }
์ฝ๋ 13-3 ์๋ชป๋ clone ๋ฉ์๋ - ๊ฐ๋ณ ์ํ๋ฅผ ๊ณต์ ํจ
@Override public HashTable clone() { try { HashTable result = (HashTable) super.clone(); result.buckets = buckets.clone(); //๋ฐฐ์ด ๋ณต์ฌ return result; } catch (CloneNotSupportedException e) { throw new AssertionError(); } }
- ๋ณต์ ๋ณธ์ ์์ ๋ง์ ๋ฒํท ๋ฐฐ์ด์ ๊ฐ์ง์ง๋ง, ์ด ๋ฐฐ์ด์ ์๋ณธ๊ณผ ๊ฐ์ ์ฐ๊ฒฐ ๋ฆฌ์คํธ๋ฅผ ์ฐธ์กฐํ์ฌ ์๋ณธ๊ณผ ๋ณต์ ๋ณธ ๋ชจ๋ ์๊ธฐ์น ์๊ฒ ๋์ํ ๊ฐ๋ฅ์ฑ์ด ์๊น
๋ค์์ ์ผ๋ฐ์ ์ธ ํด๋ฒ์
์ฝ๋ 13-4 ๋ณต์กํ ๊ฐ๋ณ ์ํ๋ฅผ ๊ฐ๋ ํด๋์ค์ฉ ์ฌ๊ท์ clone ๋ฉ์๋
public class HashTable implements Cloneable { private Entry[] buckets = ...; 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()); } } @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(); } } ... }
- private ํด๋์ค์ธ HashTable.Entry์ ๊น์๋ณต์ฌ๋ฅผ ์ถ๊ฐํจ
- HashTable์ clone ๋ฉ์๋๋
- ์ ์ ํ ํฌ๊ธฐ์ ์๋ก์ด ๋ฒํท ๋ฐฐ์ด ํ ๋น
- ์๋์ ๋ฒํท ๋ฐฐ์ด์ ์ํํ๋ฉฐ ๋น์ง ์์ ๊ฐ ๋ฒํท์ ๋ํด ๊น์๋ณต์ฌ๋ฅผ ์ํํจ
- ๋จ์
- ์ฌ๊ท ํธ์ถ๋ก ๋ฆฌ์คํธ์ด ์์ ์๋งํผ ์คํ ํ๋ ์์ ์๋นํจ
- ๋ฆฌ์คํธ๊ฐ ๊ธธ๋ฉด ์คํ ์ค๋ฒํ๋ก์ฐ๋ฅผ ์ผ์ผํฌ ์ํ์ด ์์
- ์ด ๋ฌธ์ ๋ฅผ ํผํ๋ ค๋ฉด deepCopy๋ฅผ ์ฌ๊ท ํธ์ถ ๋์ ๋ฐ๋ณต์๋ฅผ ์จ์ ์ํํ๋ ๋ฐฉํฅ์ผ๋ก ์์ ํด์ผ ํจ
์ฝ๋ 13-5 ์ํธ๋ฆฌ ์์ ์ด ๊ฐ๋ฆฌํค๋ ์ฐ๊ฒฐ ๋ฆฌ์คํธ๋ฅผ ๋ฐ๋ณต์ ์ผ๋ก ๋ณต์ฌํจ
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; }
c) ๋ง์ง๋ง ๋ฐฉ๋ฒ
- super.clone์ ํธ์ถํ์ฌ ์ป์ ๊ฐ์ฒด์ ๋ชจ๋ ํ๋๋ฅผ ์ด๊ธฐ ์ํ๋ก ์ค์ ํ ํ, ์๋ณธ ๊ฐ์ฒด์ ์ํ๋ฅผ ๋ค์ ์์ฑํ๋ ๊ณ ์์ค ๋ฉ์๋๋ค์ ํธ์ถํจ
- ์์
- HashTable ์๋ฅผ ๋ณด๋ฉด, buckets ํ๋๋ฅผ ์๋ก์ด ๋ฒํท ๋ฐฐ์ด๋ก ์ด๊ธฐํํจ
- ์๋ณธ ํ ์ด๋ธ์ ๋ด๊ธด ๋ชจ๋ ํค-๊ฐ ์ ๊ฐ๊ฐ์ ๋ํด ๋ณต์ ๋ณธ ํ ์ด๋ธ์ put(key, value) ๋ฉ์๋๋ฅผ ํธ์ถํด ๋์ ๋ด์ฉ์ด ๊ฐ๊ฒ ํด์ฃผ๋ฉด ๋จ
- ํน์ง
- Cloneable ์ํคํ ์ฒ์ ๊ธฐ์ด๊ฐ ๋๋ ํ๋ ๋จ์ ๊ฐ์ฒด ๋ณต์ฌ๋ฅผ ์ฐํํ๊ธฐ ๋๋ฌธ์ ์ ์ฒด Cloneable ์ํคํ ์ฒ์๋ ์ด์ธ๋ฆฌ์ง ์๋ ๋ฐฉ์์
์ฃผ์์ฌํญ
- ์์ฑ์์์๋ ์ค๋ฒ๋ผ์ด๋ฉ ํ ์ ์๋ ๋ฉ์๋๋ฅผ ํธ์ถํ์ง ์์์ผ ํจ
- ์์์ฉ ํด๋์ค๋ Cloneable์ ๊ตฌํํ์ง ์๋ ๊ฒ์ด ์ข์ - ์์
- Cloneable์ ๊ตฌํํ thread-safeํ ํด๋์ค๋ฅผ ์์ฑํ ๋๋ clone ๋ฉ์๋ ์ญ์ ๋๊ธฐํํด์ค์ผ ํจ
<clone ๋์ ๊ถ์ฅํ๋ ๋ฐฉ๋ฒ>
- ๋ณต์ฌ ์์ฑ์์ ๋ณต์ฌ ํฉํฐ๋ฆฌ๋ฅผ ์ฌ์ฉํ ๋ ๋์ ๊ฐ์ฒด ๋ณต์ฌ ๋ฐฉ์์ ์ ๊ณตํ ์ ์์
- ๋ณต์ฌ ์์ฑ์?
- ๋จ์ํ ์์ ๊ณผ ๊ฐ์ ํด๋์ค์ ์ธ์คํด์ค๋ฅผ ์ธ์๋ก ๋ฐ๋ ์์ฑ์๋ฅผ ๋งํจ
- ๋ณต์ฌ ์์ฑ์?
์ฝ๋ 13-7 ๋ณต์ฌ ์์ฑ์
public Yum(Yum yum) { ... }
์ฝ๋ 13-8 ๋ณต์ฌ ํฉํฐ๋ฆฌ
public static Yum newInstance(Yum yum) { ... }
- ์์ ๊ฐ์ ์ธํฐํ์ด์ค ๊ธฐ๋ฐ ๋ณต์ฌ ์์ฑ์์ ๋ณต์ฌ ํฉํฐ๋ฆฌ๋ฅผ '๋ณํ ์์ฑ์'์ '๋ณํ ํฉํฐ๋ฆฌ' ๋ผ๊ณ ํจ
- ํด๋ผ์ด์ธํธ๋ ์๋ณธ์ ๊ตฌํ ํ์ ์ ์ฝ๋งค์ด์ง ์๊ณ ๋ณต์ ๋ณธ์ ํ์ ์ ์ง์ ์ ํํ ์ ์์
๐ํต์ฌ ์ ๋ฆฌ
- Cloneable๋ก ์ธํ ๋ฌธ์ ์ ์ ๋์ง์ด๋ดค์ ๋, ์๋ก์ด ์ธํฐํ์ด์ค๋ฅผ ๋ง๋ค ๋๋ ์ ๋ Cloneable์ ํ์ฅํด์๋ ์ ๋๋ฉฐ, ์๋ก์ด ํด๋์ค๋ ์ด๋ฅผ ๊ตฌํํด์๋ ์๋จ
- final ํด๋์ค๋ผ๋ฉด Cloneable์ ๊ตฌํํด๋ ์ํ์ด ํฌ์ง ์์ง๋ง, ์ฑ๋ฅ ์ต์ ํ ๊ด์ ์์ ๊ฒํ ํ ํ ๋ณ๋ค๋ฅธ ๋ฌธ์ ๊ฐ ์์ ๋๋ง ๋๋ฌผ๊ฒ ํ์ฉํด์ผ ํจ (์์ดํ 67)
- ๊ธฐ๋ณธ ์์น์ '๋ณต์ ๊ธฐ๋ฅ์ ์์ฑ์๋ ํฉํฐ๋ฆฌ๋ฅผ ์ด์ฉํ๋ ๊ฒ ์ต๊ณ ' ๋ผ๋ ๊ฒ์
- ๋จ, ๋ฐฐ์ด๋ง์ clone ๋ฉ์๋ ๋ฐฉ์์ด ๊ฐ์ฅ ๊น๋ํ๊ณ ์ด ๊ท์น์ ํฉ๋นํ ์์ธ๋ผ ํ ์ ์์
์ฝ์ด๋ณผ ๊ฒ
'DevBook > Effective Java' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
์์ดํ 14. Comparable์ ๊ตฌํํ ์ง ๊ณ ๋ คํ๋ผ (0) 2023.05.07 ์์ดํ 12. toString์ ํญ์ ์ฌ์ ์ํ๋ผ (0) 2023.05.07 ์์ดํ 11. equals๋ฅผ ์ฌ์ ์ํ๋ ค๊ฑฐ๋ hashCode๋ ์ฌ์ ์ํ๋ผ (0) 2023.05.07 ์์ดํ 10. equals๋ ์ผ๋ฐ ๊ท์ฝ์ ์ง์ผ ์ฌ์ ์ํ๋ผ (0) 2023.05.06 3์ฅ - ๋ชจ๋ ๊ฐ์ฒด์ ๊ณตํต ๋ฉ์๋ (0) 2023.05.06 - Cloneable์ ๋ณต์ ํด๋ ๋๋ ํด๋์ค์์ ๋ช
์ํ๋ ์ฉ๋์ธ mixin ์ธํฐํ์ด์ค์ง๋ง, ์์ฝ๊ฒ๋ ์๋ํ ๋ชฉ์ ์ ์ ๋๋ก ์ด๋ฃจ์ง ๋ชปํ์