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?