2023. 2. 1. 17:04ใJAVA/Effective JAVA
item13. clone ์ฌ์ ์๋ ์ฃผ์ํด์ ์งํํ๋ผ.
https://hyejin.tistory.com/1039
-> ์์ ๊ฒ์๊ธ์ ์์์ฒ๋ผ ๋ถ๋ณ ํด๋์ค๋ Cloneable ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๊ณ , clone()์ ์ฌ์ ์ํด์ฃผ๋ฉด ๋๋๋ฐ
clone()์ ๋จ์ํ ๊ฐ์ฒด์ ์ ์ฅ๋ ๊ฐ์ ๊ทธ๋๋ก ๋ณต์ฌํ ๋ฟ, ๊ฐ์ฒด๊ฐ ์ฐธ์กฐํ๊ณ ์๋ ๊ฐ์ฒด๊น์ง ๋ณต์ฌํ์ง๋ ์๊ธฐ ๋๋ฌธ์
๊ฐ๋ณ ๊ฐ์ฒด์ ๊ฒฝ์ฐ์๋ ์ฃผ์ํ ์ ์ด ์๋ค.
shallow copy ์์ ๋ณต์ฌ
: ์๋ณธ๊ณผ ๋ณต์ฌ๋ณธ์ด ๊ฐ์ ๊ฐ์ฒด๋ฅผ ๊ณต์ ํ๋ค. -> ์๋ณธ์ ๋ณ๊ฒฝํ๋ฉด ๋ณต์ฌ๋ณธ์๋ ์ํฅ์ ๋ฐ๋๋ค.
package chapter02.item13;
import java.security.Signature;
import java.util.Arrays;
import java.util.EmptyStackException;
/**
* item13. clone ์ฌ์ ์๋ ์ฃผ์ํด์ ์งํํ๋ผ.
* ๊ฐ๋ณ ๊ฐ์ฒด clone ์ ์ํ๋ ๋ฐฉ๋ฒ - shallow copy
*/
public class Stack implements Cloneable{
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 o) {
ensureCapacity();
elements[size++] = o;
}
public Object pop() {
if (size == 0) {
throw new EmptyStackException();
}
Object result = elements[--size];
elements[size] = null; // ๋ค ์ด ์ฐธ์กฐ ํด์
return result;
}
public boolean isEmpty() {
return size == 0;
}
@Override
public Stack clone() {
try {
Stack result = (Stack) super.clone();
return result;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
// ์์๋ฅผ ์ํ ๊ณต๊ฐ์ ์ ์ด๋ ํ๋ ์ด์ ํ๋ณดํ๋ค.
private void ensureCapacity() {
if (elements.length == size) {
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}
public static void main(String[] args) {
Object[] values = new Object[2];
values[0] = new PhoneNumber(123, 456, 7890);
values[1] = new PhoneNumber(321, 765, 4321);
Stack stack = new Stack();
for (Object arg : values) {
stack.push(arg);
}
Stack copy = stack.clone();
System.out.println("pop from stack");
while (!stack.isEmpty()) {
System.out.println(stack.pop() + " ");
}
System.out.println();
System.out.println("pop from copy");
while (!copy.isEmpty()) {
System.out.println(copy.pop() + " ");
}
System.out.println();
System.out.println("stack.elements[0] == copy.elements[0] = " + (stack.elements[0] == copy.elements[0]));
}
}
๋ง์ฝ clone() ์ ์์ ๊ฐ์ด ํ๋คํ๋ฉด ์๋ณธ๊ณผ ๋ณต์ฌ๋ณธ์ด ๊ฐ์ elements๋ฅผ ๊ณต์ ํ๊ธฐ ๋๋ฌธ์
-> ์ด๋ฏธ stack์์ ๊ฐ์ ๋ค ๊บผ๋๊ธฐ ๋๋ฌธ์ copy์์๋ ๊บผ๋ผ ๊ฐ์ด ์์ด์ Null์ด ๋์ค๋ฉฐ stack์ elements์ copy์ elements ๋ฅผ ๋น๊ตํ ๋ true๊ฐ ๋ฐํ๋๋ ๊ฒ๋ ํ์ธํ ์ ์๋ค.
@Override
public Stack clone() {
try {
Stack result = (Stack) super.clone();
// elements.clone()์ ํ์ง์์ผ๋ฉด stack๊ณผ copy๊ฐ ๋์ผํ ๋ฐฐ์ด์ ์ฌ์ฉํ๊ฒ ๋๋ค!!
// ๊ทผ๋ฐ ๋ฐฐ์ด์ ์ฌ์ ํ ๋์ผํ ์ธ์คํด์ค๋ฅผ ๋ณด๊ณ ์๋ค.
// stack -> elementS[0, 1]
// copy -> elementC[0,1]
// elementS[0] == elementC[0]
result.elements = elements.clone();
return result;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
๊ทธ๋ผ clone์ ์์ ๊ฐ์ด ์ฌ์ ์ํด์ค๋ค๊ณ ํ๋ฉด
copy์๋ elements ๋ฅผ ๋ณต์ฌํด์ ๊บผ๋ผ ์ ์์ง๋ง, stack.elements ์ ๊ฐ์ฒด ๋น๊ต๋ฅผ ๋ณด๋ฉด true๊ฐ ํธ์ถ๋๋ค..!!
์ด๋ฐ ๊ฒฝ์ฐ์๋ deep copy ๊ฐ ํ์ํ๋ค.
deep copy ๊น์ ๋ณต์ฌ
: ์๋ณธ์ด ์ฐธ์กฐํ๊ณ ์๋ ๊ฐ์ฒด๊น์ง ๋ณต์ฌํ์ฌ ์๋ณธ์ ๋ณ๊ฒฝํ๋๋ผ๋ ๋ณต์ฌ๋ณธ์ ์ํฅ์ด ์๊ฒ ํ๋ ๋ณต์ฌ์ด๋ค.
package chapter02.item13;
/**
* item13. clone ์ฌ์ ์๋ ์ฃผ์ํด์ ์งํํ๋ผ.
* ๊ฐ๋ณ ๊ฐ์ฒด clone ์ ์ํ๋ ๋ฐฉ๋ฒ - deep copy
*/
public class HashTable implements Cloneable {
private Entry[] buckets = new Entry[10];
private static class Entry {
final Object key;
Object value;
Entry next;
public Entry(Object key, Object value, Entry next) {
this.key = key;
this.value = value;
this.next = next;
}
public void add(Object key, Object value) {
this.next = new Entry(key, value, null);
}
// ์ฌ๊ท์ ์ธ ๋ฐฉ๋ฒ์ StackOverflow๋ฅผ ๋ฐ์์ํฌ ์ ์๊ธฐ ๋๋ฌธ์..
public Entry deepCopy() {
return new Entry(key, value, next == null ? null : next.deepCopy());
}
}
// deep copy clone
@Override
public HashTable clone() {
HashTable result = null;
try {
result = (HashTable) super.clone();
result.buckets = new Entry[this.buckets.length]; // clone ์ฉ ๋ฐฐ์ด ์๋ก ๋ง๋ค์ด์ค
for (int i = 0; i < this.buckets.length; i++) {
if (buckets[i] != null) {
result.buckets[i] = this.buckets[i].deepCopy();
}
}
return result;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
public static void main(String[] args) {
HashTable hashTable = new HashTable();
Entry entry = new Entry(new Object(), new Object(), null);
hashTable.buckets[0] = entry;
HashTable clone = hashTable.clone();
System.out.println("(hashTable.buckets[0] == entry) = " + (hashTable.buckets[0] == entry));
System.out.println("hashTable.buckets[0] == clone.buckets[0] = " + (hashTable.buckets[0] == clone.buckets[0]));
}
}
depp copy ๋ฉ์๋๋ฅผ ๋ง๋ค์ด์ฃผ๊ณ , clone ํ ๋ clone์ฉ ๋ฐฐ์ด์ ์๋ก ๋ง๋ค์ด์ฃผ๊ณ ๊ทธ ๋ฐฐ์ด์ ๊ฐ์ ๋ฃ์ด์ค๋ค.
๊ทผ๋ฐ ์ด๋ ์์์ ๋ง๋ deep copy๋ ์ฌ๊ทํจ์๋ผ ๋ฐฐ์ด์ ํฌ๊ธฐ๋งํผ ํด๋น ๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉด ํฌ๊ธฐ๊ฐ ํฐ ๋ฐฐ์ด์ด๋ผ๋ฉด stackOverflow๊ฐ ๋ฐ์ํ ์ ์๊ธฐ ๋๋ฌธ์
์ฌ๊ทํจ์๋ณด๋ค๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค.
public 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;
}
์ด๋ ๊ฒ ๊ตฌํํ ํ์ main ๋ฉ์๋๋ฅผ ๋๋ ค๋ณด๋ฉด
์ด์ ๋ฐฐ์ด์ ๊ฐ๋ ๋ค๋ฅธ๊ฒ์ ํ์ธํ ์ ์๋ค.