Study/Effective Java
์์ดํ 13. clone ์ฌ์ ์๋ ์ฃผ์ํด์ ์งํํ๋ผ
sw_develop
2023. 5. 7. 21:02
๐์ํฉ
- 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 ๋ฉ์๋ ๋ฐฉ์์ด ๊ฐ์ฅ ๊น๋ํ๊ณ ์ด ๊ท์น์ ํฉ๋นํ ์์ธ๋ผ ํ ์ ์์
์ฝ์ด๋ณผ ๊ฒ