ITEM 13: overriding clone judiciously
public interface Cloneable {
}๋ฉ์๋ ํ๋ ์๋ Cloneable ์ธํฐํ์ด์ค๋ Object์ protected ๋ฉ์๋์ธ clone์ ๋์๋ฐฉ์์ ๊ฒฐ์ ํ๋ค. Cloneable์ ๊ตฌํํ ํด๋์ค์ ์ธ์คํด์ค์์ clone์ ํธ์ถํ๋ฉด ๊ทธ ๊ฐ์ฒด์ ํ๋๋ค์ ํ๋ํ๋ ๋ณต์ฌํ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ฉฐ, ๊ตฌํํ์ง ์์ ํด๋์ค์ ์ธ์คํด์ค์์ ํธ์ถํ๋ฉด CloneNotSupportException์ ๋์ง๋ค.
์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ค๋ ๊ฒ์ ์ผ๋ฐ์ ์ผ๋ก ํด๋น ํด๋์ค๊ฐ ๊ทธ ์ธํฐํ์ด์ค์์ ์ ์ํ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค๊ณ ์ ์ธํ๋ ํ์์ธ๋ฐ, Cloneable์ ๊ฒฝ์ฐ์๋ ์์ ํด๋์ค์ ์ ์๋ ๋์ ๋ฐฉ์์ ๋ณ๊ฒฝํ ๊ฒ์ด๋ฏ๋ก ๋ฐ๋ผํ๋ ๊ฒ์ ์ข์ง ์๋ค.
๋ถ๋ณ ํด๋์ค๋ ๊ตณ์ด clone์ ์ ๊ณตํ์ง ์๋ ๊ฒ์ด ์ข๋ค.
public final class PhoneNumber implements Cloneable{
private final short areaCode, prefix, lineNum;
private int hashCode;
@Override
public PhoneNumber clone(){
try{
// ํ๋ณํ
return (PhoneNumber) super.clone();
}catch (CloneNotSupportedException e){
throw new AssertionError();
}
}
}public class Object {
@HotSpotIntrinsicCandidate
protected native Object clone() throws CloneNotSupportedException;try-catch๋ก ๊ตฌํํ ์ด์ ๋ Object์ clone()์ด CloneNotSupportedException์ ๋์ ธ์ฃผ๊ณ ์๊ธฐ ๋๋ฌธ์ด๋ฉฐ, Cloneable์ ๊ตฌํํ๋ฉด CloneNotSupportedException์ด ๋ฐ์ํ์ง ์์ ๊ฒ์ ์๋ค.
Object ๋ฉ์๋๋ CloneNotSupportedException์ ๋์ง๋ค๊ณ ์ ์ธํ์ง๋ง, ์ฌ์ ์ํ ๋ฉ์๋์์๋ throws์ ์ ์์ ๋ ๊ฒ์ด ์ข๋ค. ๊ฒ์ฌ ์์ธ๋ฅผ ๋์ง์ง ์์์ผ ๊ทธ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๊ธฐ ํธํ๊ธฐ ๋๋ฌธ์ด๋ค.(๋น๊ฒ์ฌ ์์ธ-item71)
clone()์ ์๋ณธ ๊ฐ์ฒด์ ์๋ฌด๋ฐ ํด๋ฅผ ๋ผ์น์ง ์๋ ๋์์ ๋ณต์ ๋ ๊ฐ์ฒด์ ๋ถ๋ณ์์ ๋ณด์ฅํด์ผํ๋ค.
public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_CAPACITY = 16;
public Stack() {
elements = new Object[DEFAULT_CAPACITY];
}
public void push(Object e){
ensureCapacity();
elements[size++] = 0;
}
public Object pop(){
if(size == 0){
throw new EmptyStackException();
}
return elements[--size];
}
// ์์๋ฅผ ์ํ ๊ณต๊ฐ์ ์ ์ด๋ ํ๋ ์ด์ ์ฌ์ ๋ฅผ ๋๋ฉฐ, ๋๋ ค์ผํ๋ ๊ฒฝ์ฐ ๋๋ฐฐ ์ด์ ๋๋ฆฐ๋ค.
private void ensureCapacity(){
if(elements.length == size){
elements = Arrays.copyOf(elements, 2*size+1);
}
}
}์ stack ํด๋์ค๋ ๊ฐ๋ณ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ๊ณ ์๋ค.
@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 ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๊ถ์ฅํ๋ค.
ํํธ ์ Stack ํด๋์ค์ elements ํ๋๊ฐ final์ด์๋ค๋ฉด final ํ๋๋ ์๋ก์ด ๊ฐ์ ํ ๋นํ ์ ์๊ธฐ๋๋ฌธ์ ์ clone() ๋ฉ์๋ ๋ฐฉ์์ ์๋ํ์ง ์๋๋ค.
Cloneable ์ํคํ
์ฒ๋ ๊ฐ๋ณ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ๋ ํ๋๋ final๋ก ์ ์ธํ๋ผ๋ ์ผ๋ฐ ์ฉ๋ฒ๊ณผ ์ถฉ๋ํ๋ค. ์๋ณธ๊ณผ ๋ณต์ ๋ ๊ฐ์ฒด๊ฐ ๊ฐ๋ณ ๊ฐ์ฒด๋ฅผ ๊ณต์ ํด๋ ๋๋ค๋ฉด ์๊ด์์ง๋ง, ๋ณต์ ํ ์ ์๋ ํด๋์ค๋ฅผ ๋ง๋ค๊ธฐ ์ํด ์ผ๋ถ ํ๋์์ final ํ์ ์๋ฅผ ์ ๊ฑฐํด์ผํ ์๋ ์๋ค.
public class HashTable implements Cloneable{
private Entry[] buckets = new Entry[10];
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());
// ์คํ์ค๋ฒํ๋ก์ฐ ๋ฌธ์ ๋ฅผ ํผํ๊ธฐ ์ํด ๋ฐ๋ณต์๋ฅผ ์ฌ์ฉ
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;
}
}
/**
* ์๋ชป๋ Clone
* ์๋ณธ๊ณผ ๊ฐ์ ์ฐ๊ฒฐ ๋ฆฌ์คํธ๋ฅผ ์ฐธ์กฐ ํด ์๋ณธ๊ณผ ๋ณต์ ๋ณธ ๋ชจ๋ ์๊ธฐ์น ์๊ฒ ๋์ํ ๊ฐ๋ฅ์ฑ ์๊น
* @return
* @Override
* public HashTable clone(){
* try{
* HashTable result = (HashTable) super.clone();
* result.buckets = buckets.clone();
* return result;
* }catch (CloneNotSupportedException e){
* throw new AssertionError();
* }
* }
*/
/**
*
* @return
*/
@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 ํด๋์ค๋ฅผ ๋ณด๋ฉด, Stack๊ณผ ๋์ผํ ๋ฐฉ๋ฒ์ผ๋ก clone()์ ๊ตฌํํ๋ฉด ์๋ณธ๊ณผ ๊ฐ์ ์ฐ๊ฒฐ ๋ฆฌ์คํธ๋ฅผ ์ฐธ์กฐ ํด ์๋ณธ๊ณผ ๋ณต์ ๋ณธ ๋ชจ๋ ์๊ธฐ์น ์๊ฒ ๋์ํ ๊ฐ๋ฅ์ฑ ์๊ธธ ์ ์๊ธฐ๋๋ฌธ์, deepCopy()๋ฅผ ๋ณ๋๋ก ๊ตฌํํ์ฌ ํด๋น ์ํธ๋ฆฌ๊ฐ ๊ฐ๋ฆฌํค๋ ์ฐ๊ฒฐ ๋ฆฌ์คํธ๋ฅผ ์ฌ๊ท์ ์ผ๋ก ๋ณต์ฌํด์ฃผ์๋ค.
clone() ๋ฉ์๋๋ ์ฌ์ ์๋ ์ ์๋ ๋ฉ์๋๋ฅผ ํธ์ถํด์๋ ์๋๋ค. ๋ง์ฝ clone()์ด ํ์ ํด๋์ค์์ ์ฌ์ ์ํ ๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉด, ํ์ ํด๋์ค๋ ๋ณต์ ๊ณผ์ ์์ ์์ ์ ์ํ๋ฅผ ๊ต์ ํ ์ ์๋ ๊ธฐํ๋ฅผ ์ผ๊ฒ๋์ด ์๋ณธ๊ณผ ์ํ๊ฐ ๋ฌ๋ผ์ง ๊ฐ๋ฅ์ฑ์ด ์ปค์ง๊ฒ๋๋ค.
์์ฝํ์๋ฉด, Cloneable์ ๊ตฌํํ๋ ๋ชจ๋ ํด๋์ค๋ clone()์ ์ฌ์ ์ํด์ผ ํ๋ค. ์ด๋ ์ ๊ทผ ์ ํ์๋ public์ผ๋ก, ๋ฐํ ํ์
์ ํด๋์ค ์์ ์ผ๋ก ๋ณ๊ฒฝํ๋ค. ๊ฐ์ฅ ๋จผ์ super.clone ์ ํธ์ถํ ํ ํ์ํ ํ๋๋ฅผ ์ ๋ถ ์ ์ ํ ์์ ํด์ค์ผ ํ๋ค. ์ผ๋ฐ์ ์ผ๋ก '๊น์ ๊ตฌ์กฐ'์ ์จ์ด ์๋ ๋ชจ๋ ๊ฐ๋ณ ๊ฐ์ฒด๋ฅผ ๋ณต์ฌํ๊ณ , ๋ณต์ ๋ณธ์ด ๊ฐ์ง ๊ฐ์ฒด ์ฐธ์กฐ ๋ชจ๋๊ฐ ๋ณต์ฌ๋ ๊ฐ์ฒด๋ค์ ๊ฐ๋ฆฌํค๊ฒ ํด์ผํ๋ค. ๊ธฐ๋ณธ ํ์
ํ๋์ ๋ถ๋ณ ๊ฐ์ฒด ์ฐธ์กฐ๋ง์ ๊ฐ๋ ํด๋์ค๋ผ๋ฉด ์๋ฌด ํ๋๋ ์์ ํ ํ์๋ ์๋ค.
Cloneable์ ๊ตฌํํ์ง ์์ ํด๋์ค๋ผ๋ฉด ๋ณต์ฌ ์์ฑ์์ ๋ณต์ฌ ํฉํฐ๋ฆฌ๋ผ๋ ๋ ๋์ ๊ฐ์ฒด ๋ณต์ฌ ๋ฐฉ์์ ์ ๊ณตํ ์ ์๋ค.
// ๋ณต์ฌ์์ฑ์
public Item(Item item){...};// ๋ณต์ฌ ํฉํฐ๋ฆฌ
public static Item newInstance(Item item){...};๋ณต์ฌ ์์ฑ์๋ ๋จ์ํ ์์ ๊ณผ ๊ฐ์ ํด๋์ค์ ์ธ์คํด์ค๋ฅผ ์ธ์๋ก ๋ฐ๋ ์์ฑ์๋ฅผ ๋งํ๋ค.
๋ณต์ฌ ์์ฑ์/ํฉํฐ๋ฆฌ๋
์์ฑ์๋ฅผ ์ฐ์ง ์๋ ๋ฐฉ์์ ๊ฐ์ฒด ์์ฑ ๋ฉ์ปค๋์ฆ์ ์ฌ์ฉํ์ง ์๋๋ค.
์์ฑํ๊ฒ ๋ฌธ์ํ๋ ๊ท์ฝ์ ๊ธฐ๋์ง ์๊ณ , ์ ์์ ์ธ final ํ๋ ์ฉ๋ฒ๊ณผ๋ ์ถฉ๋ํ์ง ์๋๋ค.
๋ถํ์ํ ๊ฒ์ฌ ์์ธ๋ฅผ ๋์ง์ง ์๊ณ , ํ๋ณํ๋ ํ์์น ์๋๋ค.
ํด๋น ํด๋์ค๊ฐ ๊ตฌํํ ์ธํฐํ์ด์ค ํ์ ์ ์ธ์คํด์ค๋ฅผ ์ธ์๋ก ๋ฐ์ ์ ์๋ค.
๋ชจ๋ ๋ฒ์ฉ ์ปฌ๋ ์
๊ตฌํ์ฒด๋ Collection ์ด๋ Map ํ์
์ ๋ฐ๋ ์์ฑ์๋ฅผ ์ ๊ณตํ๋ค. ์ด๋ฅผ ์ด์ฉํ๋ฉด ํด๋ผ์ด์ธํธ๋ ์๋ณธ์ ๊ตฌํ ํ์
์ ์ฝ๋งค์ด์ง ์๊ณ ๋ณต์ ๋ณธ์ ํ์
์ ์ง์ ์ ํํ ์ ์๋ค. (HashSet์ TreeSet ํ์
์ผ๋ก ๋ณต์ ๊ฐ๋ฅ)
new TreeSet<>(s);Last updated
Was this helpful?