item 13 sijun - JAVA-JIKIMI/EFFECTIVE-JAVA3 GitHub Wiki
Clone ๋ฉ์๋
์๋ณธ ๊ฐ์ฒด์ ํ๋๊ฐ๊ณผ ๋์ผํ ๊ฐ์ ๊ฐ์ง๋ ์๋ก์ด ๊ฐ์ฒด๋ฅผ ์์ฑํด ์ฃผ๋ ๋ฉ์๋
Shallow ๋ณต์ฌ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๋ฉฐ, ๋ง์ฝ ๊ฐ์ฒด๊ฐ ์ฐธ์กฐํ์ ์ ๋ฉค๋ฒ๋ฅผ ๊ฐ์ง๊ณ ์๋ค๋ฉด ์ฐธ์กฐ๊ฐ๋ง ๋ณต์ฌํ๋ ํน์ง์ด ์๋ค.
์๋ ์ฝ๋์์ s1๊ณผ s2๋ ๊ฐ์ name
ํ๋๋ฅผ ๊ฐ์ง๊ฒ ๋์ง๋ง, s1 == s2
๋ false
์ด๋ค.
class Student implements Cloneable{
String name;
Student(String name){
this.name = name;
}
protected Object clone() throws CloneNotSupportedException{
return super.clone();
}
}
class Main {
public static void main(String[] args) {
Student s1 = new Student("ํ๊ธธ๋");
try {
Student s2 = (Student)s1.clone();
System.out.println(s1.name);
System.out.println(s2.name);
System.out.println(s1 == s2);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
Cloneable
์ ์ญํ
Cloneable
์ ๋ณต์ ํด๋ ๋๋ ํด๋์ค์์ ๋ช
์ํ๋ ์ฉ๋๋ก ์ฐ์ธ๋ค. Cloneable
์ธํฐํ์ด์ค ๋ด์๋ clone
๋ฉ์๋๊ฐ ์๋ค. clone
๋ฉ์๋๊ฐ ์ ์ธ๋ ๊ณณ์ Object
์ด๋ฉฐ protected
์ด๊ธฐ์, Coneable
์ ๊ตฌํํ๋ ๊ฒ๋ง์ผ๋ก๋ ์ธ๋ถ ๊ฐ์ฒด์์ clone
๋ฉ์๋๋ฅผ ํธ์ถํ ์ ์๋ค.
๋ฉ์๋ ํ๋ ์๋ Cloneable
์ธํฐํ์ด์ค๋ Object
์ protected ๋ฉ์๋์ธ clone
์ ๋์ ๋ฐฉ์์ ๊ฒฐ์ ํ๋ค.
Cloneable
์ ๊ตฌํ โ ๊ฐ์ฒด์ ํ๋๋ค์ ํ๋ํ๋ ๋ณต์ฌํ ๊ฐ์ฒด ๋ฐํCloneable
์ ๋ฏธ๊ตฌํ โCloneNotSupportedException
์ ๋์ง
Cloneable
์ฌ์ฉ ์ ์ฃผ์ํ ์
1. ๊ฐ๋ณ ๊ฐ์ฒด ์ฐธ์กฐ CASE
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];
}
public void push(Object e) {
ensureCapacity();
elements[size++] = e;
}
public Object pop() {
if (size == 0)
throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null;
return result;
}
// ์์๋ฅผ ์ํ ๊ณต๊ฐ์ ์ ์ด๋ ํ๋ ์ด์ ํ๋ณดํ๋ค.
private void ensureCapacity() {
if (elements.length == size)
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}
์ ํด๋์ค๋ฅผ ๋ณต์ ๊ฐ๋ฅํ๊ฒ ๋ง๋ ๋ค๋ฉด, array
ํ์
์ elements
ํ๋๋ ์๋ณธ๊ณผ ๊ฐ์ ๋ฐฐ์ด์ ์ฐธ์กฐํ๊ฒ ๋๋ค. ์ฆ, ๋ฐฐ์ด์ ๋ณต์ฌํ ๋ ๋จ์ํ clone()
๋ง ๊ตฌํํ๋ค๋ฉด ์๋ชป๋ ๊ฒฐ๊ณผ๋ฅผ ๋ง๋ ๋ค.
์ด๋ฌ๋ฉด ๋ถ๋ณ์์ ํด์น๊ฒ ๋๊ณ ํ๋ก๊ทธ๋จ์ด ์ด์ํ๊ฒ ์๋ํ ์ ์๋ค.
๋ฐ๋ผ์ clone ๋ฉ์๋๋ ๋ณธ ๊ฐ์ฒด์ ์๋ฌด๋ฐ ํด๋ฅผ ๋ผ์น์ง ์๋ ๋์์ ๋ณต์ ๋ ๊ฐ์ฒด์ ๋ถ๋ณ์์ ๋ณด์ฅํด์ผ ํ๋ค.
์ฌ๋ฐ๋ฅธ ๋ฐฐ์ด ๋ณต์ฌ
๋ฐ๋ผ์ array type์ ํ๋๋ก ๊ฐ๋ class๋ ๋ฐฐ์ด์ ์๋์ ๊ฐ์ ๋ฐฉ๋ฒ์ผ๋ก ๊ฐ๊ฐ cloneํด์ผ ํ๋ค.
@Override public Stack clone() {
try {
Stack result = (Stack) super.clone();
result.elements = elements.clone();
return result;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
2. Stack Overflow CASE
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();
}
}
... // ๋๋จธ์ง ์ฝ๋๋ ์๋ต
}
์ ์์ ์์ HashTable
ํด๋์ค๋ buckets
์ด๋ผ๋ Entry ํ์
์ array๋ฅผ ํ๋๋ก ๊ฐ์ง๋ค. Entry ํ์
์ next ํ๋๋ฅผ ํตํด ์ฐ๊ฒฐ ๋ฆฌ์คํธ๋ฅผ ์ฐธ์กฐํ๊ณ ์๋ค.
์ ์ฝ๋์์ ๋ณผ ์ ์๋์, HashTable clone ๋ฉ์๋๋ deep copy๋ฅผ ์ง์ํ๋ค. clone ๋ฉ์๋๋ ๋จผ์ ์ ์ ํ ํฌ๊ธฐ์ ์๋ก์ด ๋ฒํท ๋ฐฐ์ด์ ํ ๋นํ๊ณ , ๊น์ ๋ณต์ฌ๋ฅผ ์ํํ๋ค. ์ด ๋ Entry์ deepCopy ๋ฉ์๋๋ ์์ ์ด ๊ฐ๋ฆฌํค๋ ์ฐ๊ฒฐ ๋ฆฌ์คํธ ์ ์ฒด๋ฅผ ๋ณต์ฌํ๊ธฐ ์ํด ์์ ์ ์ฌ๊ท์ ์ผ๋ก ํธ์ถํ๋ค. ํ์ง๋ง ์ฐ๊ฒฐ ๋ฆฌ์คํธ๋ฅผ ๋ณต์ ํ๋ ๋ฐฉ๋ฒ์ผ๋ก๋ ์ ์ ํ์ง ์๋ค. ์ฌ๊ท ํธ์ถ ๋๋ฌธ์ ๋ฆฌ์คํธ์ ์์ ์๋งํผ ์คํ ํ๋ ์์ ์๋นํ์ฌ, ๋ฆฌ์คํธ๊ฐ ๊ธธ๋ฉด ์คํ ์ค๋ฒํ๋ก๋ฅผ ์ผ์ผํฌ ์ํ์ด ์๊ธฐ ๋๋ฌธ์ด๋ค.
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ ๋ฐฉ๋ฒ์ deepCopy
๋ฅผ ์ฌ๊ท ํธ์ถ ๋์ ๋ฐ๋ณต์๋ฅผ ์ฐ๋ ๊ฒ์ด๋ค. ์๋ ์ฝ๋ ์ฐธ์กฐ.
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;
}
Cloneable ์ฌ์ฉ๋ฒ ์ ๋ฆฌ
Cloneable์ ๊ตฌํํ๋ ๋ชจ๋ ํด๋์ค๋ clone์ ์ฌ์ ์ํด์ผ ํ๋ค. ์ด๋ ์ ๊ทผ ์ ํ์๋ public์ผ๋ก, ๋ฐํ ํ์ ์ ํด๋์ค ์์ ์ผ๋ก ๋ณ๊ฒฝํ๋ค. ์ด ๋ฉ์๋๋ ๊ฐ์ฅ ๋จผ์ super.clone์ ํธ์ถํ ํ ํ์ํ ํ๋๋ฅผ ์ ๋ถ ์ ์ ํ ์์ ํ๋ค. ์ผ๋ฐ์ ์ผ๋ก ์ด ๋ง์ ๊ทธ ๊ฐ์ฒด์ ๋ด๋ถ '๊น์ ๊ตฌ์กฐ'์ ์จ์ด ์๋ ๋ชจ๋ ๊ฐ๋ณ ๊ฐ์ฒด๋ฅผ ๋ณต์ฌํ๊ณ , ๋ณต์ ๋ณธ์ด ๊ฐ์ง ๊ฐ์ฒด ์ฐธ์กฐ ๋ชจ๋๊ฐ ๋ณต์ฌ๋ ๊ฐ์ฒด๋ค์ ๊ฐ๋ฆฌํค๊ฒ ํจ์ ๋ปํ๋ค. ์ด๋ฌํ ๋ด๋ถ ๋ณต์ฌ๋ ์ฃผ๋ก clone์ ์ฌ๊ท์ ์ผ๋ก ํธ์ถํด ๊ตฌํํ์ง๋ง, ์ด ๋ฐฉ์์ด ํญ์ ์ต์ ์ธ ๊ฒ์ ์๋๋ค. ๊ธฐ๋ณธ ํ์ ํ๋์ ๋ถ๋ณ ๊ฐ์ฒด ์ฐธ์กฐ๋ง ๊ฐ๋ ํด๋์ค๋ผ๋ฉด ์๋ฌด ํ๋๋ ์์ ํ ํ์๊ฐ ์๋ค. ๋จ, ์ผ๋ จ๋ฒํธ๋ ๊ณ ์ IDsms ๋น๋ก ๊ธฐ๋ณธ ํ์ ์ด๋ ๋ถ๋ณ์ผ์ง๋ผ๋ ์์ ํด์ค์ผ ํ๋ค.
Cloneable ๋์
๋ณต์ฌ ์์ฑ์์ ๋ณต์ฌ ํฉํฐ๋ฆฌ๋ผ๋ ๋ ๋์ ๊ฐ์ฒด ๋ณต์ฌ ๋ฐฉ์์ ์ ๊ณตํ ์ ์๋ค.
๋ณต์ฌ ์์ฑ์๋ ๋จ์ํ ์์ ๊ณผ ๊ฐ์ ํด๋์ค์ ์ธ์คํด์ค๋ฅผ ์ธ์๋ก ๋ฐ๋ ์์ฑ์๋ฅผ ๋งํ๋ค.
// ๋ณต์ฌ ์์ฑ์
public Yum(Yum yum) {...};
// ๋ณต์ฌ ํฉํฐ๋ฆฌ
public static Yum newInstance(Yum yum) {...};
๋ณต์ฌ ์์ฑ์์ ๊ทธ ๋ณํ์ธ ๋ณต์ฌ ํฉํฐ๋ฆฌ๋ Cloneable๊ณผ Clone ๋ฐฉ์๋ณด๋ค ๋์ ์ ์ด ๋ง๋ค.
์ธ์ด ๋ชจ์์ ์ด๊ณ ์ํ์ฒ๋งํ ๊ฐ์ฒด ์์ฑ ๋ฉ์ปค๋์ฆ(์์ฑ์๋ฅผ ์ฐ์ง ์๋ ๋ฐฉ์)์ ์ฌ์ฉํ์ง ์์ผ๋ฉฐ, ์์ฑํ๊ฒ ๋ฌธ์ํ๋ ๊ท์ฝ์ ๊ธฐ๋์ง ์๊ณ , ์ ์์ ์ธ final ํ๋ ์ฉ๋ฒ๊ณผ๋ ์ถฉ๋ํ์ง ์์ผ๋ฉฐ, ๋ถํ์ํ ๊ฒ์ฌ ์์ธ๋ฅผ ๋์ง์ง ์๊ณ , ํ๋ณํ๋ ํ์์น ์๋ค.
๋ํ, ๋ณต์ฌ ์์ฑ์์ ๋ณต์ฌ ํํฐ๋ฆฌ๋ ํด๋น ํด๋์ค๊ฐ ๊ตฌํํ '์ธํฐํ์ด์ค' ํ์ ์ ์ธ์คํด์ค๋ฅผ ์ธ์๋ก ๋ฐ์ ์ ์๋ค. ์ด๋ค์ ์ด์ฉํ์ฌ HashSet ๊ฐ์ฒด s๋ฅผ TreeSet ํ์ ์ผ๋ก ๋ณต์ ํ ์ ์๋ค.