item 13 incheol - JAVA-JIKIMI/EFFECTIVE-JAVA3 GitHub Wiki
Effective Java 3e ์์ดํ 13๋ฅผ ์์ฝํ ๋ด์ฉ ์ ๋๋ค.
๋ฉ์๋ ํ๋ ์๋ cloneable ์ธํฐํ์ด์ค๋ ๋์ฒด ๋ฌด์จ ์ผ์ ํ ๊น?
์ด ์ธํฐํ์ด์ค๋ Object์ protected ๋ฉ์๋์ธ clone์ ๋์ ๋ฐฉ์์ ๊ฒฐ์ ํ๋ค. Cloneable
์ ๊ตฌํํ ํด๋์ค์ ์ธ์คํด์ค์์ clone
์ ํธ์ถํ๋ฉด ๊ทธ ๊ฐ์ฒด์ ํ๋๋ค์ ํ๋ํ๋ ๋ณต์ฌํ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ฉฐ, ๊ทธ๋ ์ง ์์ ํด๋์ค์ ์ธ์คํด์ค์์ ํธ์ถํ๋ฉด CloneNotSupportedException
์ ๋์ง๋ค.
public class Stack {
private Object[] elements;
private int size = 0;
...
}
Stack ํด๋์ค๋ฅผ clone ํ๋ฉด ์ด๋ป๊ฒ ๋ ๊น?
๋ฐํ๋ Stack ์ธ์คํด์ค์ size ํ๋๋ ์ฌ๋ฐ๋ฅธ ๊ฐ์ ๊ฐ๊ฒ ์ง๋ง, elements
ํ๋๋ ์๋ณธ Stack ์ธ์คํด์ค์ ๋๊ฐ์ ๋ฐฐ์ด์ ์ฐธ์กฐํ ๊ฒ์ด๋ค. ์๋ณธ์ด๋ ๋ณต์ ๋ณธ ์ค ํ๋๋ฅผ ์์ ํ๋ฉด ๋ค๋ฅธ ํ๋๋ ์์ ๋์ด ๋ถ๋ณ์์
ํด์น๋ค๋ ์ด์ผ๊ธฐ๋ค.
clone ๋ฉ์๋๋ ์ฌ์ค์ ์์ฑ์์ ๊ฐ์ ํจ๊ณผ๋ฅผ ๋ธ๋ค.
์ฆ, clone์ ์๋ณต ๊ฐ์ฒด์ ์๋ฌด๋ฐ ํด๋ฅผ ๋ผ์น์ง ์๋ ๋์์ ๋ณต์ ๋ ๊ฐ์ฒด์ ๋ถ๋ณ์์ ๋ณด์ฅํด์ผ ํ๋ค.
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ๊ฐ์ฅ ์ฌ์ด ๋ฐฉ๋ฒ์ elements
๋ฐฐ์ด์ clone์ ์ฌ๊ท์ ์ผ๋ก
ํธ์ถํด์ฃผ๋ ๊ฒ์ด๋ค.
@Override
public Stack clone() {
try {
Stack result = (Stack) super.clone();
result.elements = elements.clone();
return result;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
๋ฐ๋ผ์ ๋ฐฐ์ด์ ๋ณต์ ํ ๋๋ ๋ฐฐ์ด์ clone ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ผ๊ณ ๊ถ์ฅํ๋ค.
๊ทธ๋ฐ๋ฐ clone์ ์ฌ๊ท์ ์ผ๋ก ํธ์ถํ๋ ๊ฒ๋ง์ผ๋ก๋ ์ถฉ๋ถํ์ง ์์ ๋๋ ์๋ค. ์ด๋ฒ์๋ ํด์ํ
์ด๋ธ์ฉ 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;
}
}
... // ๋๋จธ์ง ์ฝ๋๋ ์๋ต
}
@Override
public HashTable clone() {
try {
HashTable result = (HashTable) super.clone();
result.buckets = buckets.clone();
return result;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
๋ณต์ ๋ณธ์ ์์ ๋ง์ ๋ฒํท ๋ฐฐ์ด์ ๊ฐ์ง๋ง, ์ด ๋ฐฐ์ด์ ์๋ณธ๊ณผ ๊ฐ์ ์ฐ๊ฒฐ ๋ฆฌ์คํธ๋ฅผ ์ฐธ์กฐํ์ฌ ์๋ณธ๊ณผ ๋ณต์ ๋ณธ ๋ชจ๋ ์๊ธฐ์น ์๊ฒ ๋์ํ ๊ฐ๋ฅ์ฑ์ด ์๊ธด๋ค.
์ด๋ฅผ ํด๊ฒฐํ๋ ค๋ฉด ๊ฐ ๋ฒํท์ ๊ตฌ์ฑํ๋ ์ฐ๊ฒฐ ๋ฆฌ์คํธ๋ฅผ ๋ณต์ฌํด์ผ ํ๋ค.
public class HashTable implements Cloneable {
...
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();
}
}
์ด๋ Entry์ deepCopy ๋ฉ์๋๋ ์์ ์ด ๊ฐ๋ฆฌํค๋ ์ฐ๊ฒฐ ๋ฆฌ์คํธ ์ ์ฒด๋ฅผ ๋ณต์ฌํ๊ธฐ ์ํด ์์ ์ ์ฌ๊ท์ ์ผ๋ก ํธ์ถํ๋ค.
Cloneable์ ๊ตฌํํ๋ ๋ชจ๋ ํด๋์ค๋ clone์ ์ฌ์ ์ํด์ผ ํ๋ค. ์ด๋ ์ ๊ทผ ์ ํ์๋ public์ผ๋ก ๋ฐํ ํ์
์ ํด๋์ค ์์ ์ผ๋ก ๋ณ๊ฒฝํ๋ค. ์ด ๋ฉ์๋๋ ๊ฐ์ฅ ๋จผ์ super.clone
์ ํธ์ถํ ํ ํ์ํ ํ๋๋ฅผ ์ ๋ถ ์ ์ ํ ์์ ํ๋ค.
๊ธฐ๋ณธ ํ์ ํ๋์ ๋ถ๋ณ ๊ฐ์ฒด ์ฐธ์กฐ๋ง ๊ฐ๋ ํด๋์ค๋ผ๋ฉด ์๋ฌด ํ๋๋ ์์ ํ ํ์๊ฐ ์๋ค. ๋จ, ์ผ๋ จ๋ฒํธ๋ ๊ณ ์ ID๋ ๋น๋ก ๊ธฐ๋ณธ ํ์ ์ด๋ ๋ถ๋ณ์ผ์ง๋ผ๋ ์์ ํด์ค์ผ ํ๋ค.
๊ทธ๋ฐ๋ฐ ์ด ๋ชจ๋ ์์ ์ด ๊ผญ ํ์ํ ๊ฑธ๊น?
๋คํํ๋ ์ด์ฒ๋ผ ๋ณต์กํ ๊ฒฝ์ฐ๋ ๋๋ฌผ๋ค. Cloneable์ ์ด๋ฏธ ๊ตฌํํ ํด๋์ค๋ฅผ ํ์ฅํ๋ค๋ฉด ์ด์ฉ ์ ์์ด clone์ ์ ์๋ํ๋๋ก ๊ตฌํํด์ผ ํ๋ค. ๊ทธ๋ ์ง ์์ ์ํฉ์์๋ ๋ณต์ฌ ์์ฑ์
์ ๋ณต์ฌ ํฉํฐ๋ฆฌ
๋ผ๋ ๋ ๋์ ๊ฐ์ฒด ๋ณต์ฌ ๋ฐฉ์์ ์ ๊ณตํ ์ ์๋ค. ๋ณต์ฌ ์์ฑ์
๋ ๋จ์ํ ์์ ๊ณผ ๊ฐ์ ํด๋์ค์ ์ธ์คํด์ค๋ฅผ ์ธ์๋ก ๋ฐ๋ ์์ฑ์๋ฅผ ๋งํ๋ค.
๋ณต์ฌ ์์ฑ์์ ๋ณต์ฌ ํฉํฐ๋ฆฌ๋ ํด๋น ํด๋์ค๊ฐ ๊ตฌํํ '์ธํฐํ์ด์ค'
ํ์
์ ์ธ์คํด์ค๋ฅผ ์ธ์๋ก ๋ฐ์ ์ ์๋ค.
ํต์ฌ ์ ๋ฆฌ
Cloneable
์ด ๋ชฐ๊ณ ์จ ๋ชจ๋ ๋ฌธ์ ๋ฅผ ๋์ง์ด๋ดค์ ๋, ์๋ก์ด ์ธํฐํ์ด์ค๋ฅผ ๋ง๋ค ๋๋ ์ ๋ Cloneable์ ํ์ฅํด์๋ ์ ๋๋ฉฐ, ์๋ก์ด ํด๋์ค๋ ์ด๋ฅผ ๊ตฌํํด์๋ ์ ๋๋ค. final ํด๋์ค๋ผ๋ฉด Cloneable์ ๊ตฌํํด๋ ์ํ์ด ํฌ์ง ์์ง๋ง, ์ฑ๋ฅ ์ต์ ํ ๊ด์ ์์ ๊ฒํ ํ ํ ๋ณ๋ค๋ฅธ ๋ฌธ์ ๊ฐ ์์ ๋๋ง ๋๋ฌผ๊ฒ ํ์ฉํด์ผ ํ๋ค.
๊ธฐ๋ณธ ์์น์ '๋ณต์ ๊ธฐ๋ฅ์ ์์ฑ์์ ํฉํฐ๋ฆฌ๋ฅผ ์ด์ฉํ๋ ๊ฒ ์ต๊ณ
'๋ผ๋ ๊ฒ์ด๋ค. ๋จ, ๋ฐฐ์ด๋ง์ clone ๋ฉ์๋ ๋ฐฉ์์ด ๊ฐ์ฅ ๊น๋ํ ์ด ๊ท์น์ ํฉ๋นํ ์์ธ๋ผ ํ ์ ์๋ค.