13. clone ์ฌ์ ์๋ ์ฃผ์ํด์ ์งํ
- Cloneable : ๋ณต์ ํด๋ ๋๋ ํด๋์ค์์ ๋ช
์ํ๋ ์ฉ๋์ ์ธํฐํ์ด์ค
- Object์ protected ๋ฉ์๋์ธ clone์ ๋์ ๋ฐฉ์์ ๊ฒฐ์
- Cloneable์ ์์ ํด๋์ค์ ์ ์๋ protected ๋ฉ์๋์ ๋์ ๋ฐฉ์์ ๋ณ๊ฒฝ
- ์์ ๊ด๊ณ์ ๋ ํด๋์ค ์ค ํ์ ํด๋์ค์์ super.clone์ ํธ์ถํ๋ค๋ฉด ์๋ชป๋ ํด๋์ค์ ๊ฐ์ฒด๊ฐ ๋ง๋ค์ด์ง ์ ์์
๐ ํด๋์ค B๊ฐ ํด๋์ค A๋ฅผ ์์ํ ๋, ํ์ ํด๋์ค์ธ B์ clone์ B ํ์ ๊ฐ์ฒด๋ฅผ ๋ฐํํด์ผ ํจ. ํ์ง๋ง A์ clone์ด new A(...)๋ก ์์ฑํ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ค๋ฉด, B์ clone๋ A ํ์ ๊ฐ์ฒด๋ฅผ ๋ฐํ.
โณ๏ธ ๊ฐ๋ณ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ๋ Stack ํด๋์ค ๋ณต์ ํ๊ธฐ
public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {
elements = new Object[DEFAULT_INITIAL_CAPACITY];
}
...
}
- clone ๋ฉ์๋๊ฐ ๋จ์ํ super.clone์ ๊ฒฐ๊ณผ๋ฅผ ๊ทธ๋๋ก ๋ฐํํ๋ค๋ฉด elements ํ๋๋ ์๋ณธ Stack ์ธ์คํด์ค์ ๋๊ฐ์ ๋ฐฐ์ด์ ์ฐธ์กฐํ๊ฒ๋จ. ๊ทธ๋ฌ๋ฏ๋ก ์๋ณธ์ด๋ ๋ณต์ ๋ณธ ์ค ํ๋๋ฅผ ์์ ํ๋ฉด ๋ค๋ฅธ ํ๋๋ ์์ ๋์ด ๋ถ๋ณ์์ ํด์นจ.
- clone ๋ฉ์๋๊ฐ ์ ๋๋ก ๋์ํ๋ ค๋ฉด ์คํ ๋ด๋ถ ์ ๋ณด๋ฅผ ๋ณต์ฌํด์ผํจ ๐ elements ๋ฐฐ์ด์ clone์ ์ฌ๊ท์ ์ผ๋ก ํธ์ถ
@Override
public Stack clone(){
try{
Stack result = (Stack) super.clone();
result.elements = elements.clone();
return result;
} catch(CloneNotSupportedException e){
throw new AssertionError();
}
}
โ ๏ธ ์๋ ์ฝ๋์ ๊ฐ์ด ์ฌ๊ท์ ํธ์ถ์ด ์ถฉ๋ถํ์ง ์์ ๋๋ ์์
public class HashTable implements Cloneable {
private Entry[] buckets = ...;
private static class Entry {
final Object key;
Object value;
Entry next;
Entry(Obejct key, Object value, Entry next) {
this.key = key;
this.value = value;
this.next = next;
}
}
...//์๋ต
}
@Override
public HashTable clone() {
try {
HashTable result = (HashTable) super.clone();
result.buckets = buckets.clone();
return result;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
- ๋ณต์ ๋ณธ์ ์์ ๋ง์ ๋ฒํท ๋ฐฐ์ด์ ๊ฐ์ง๋ง, ์ด ๋ฐฐ์ด์ ์๋ณธ๊ณผ ๊ฐ์ ์ฐ๊ฒฐ๋ฆฌ์คํธ๋ฅผ ์ฐธ์กฐํจ
- ๊ฐ ๋ฒํท์ ๊ตฌ์ฑํ๋ ์ฐ๊ฒฐ๋ฆฌ์คํธ๋ฅผ ๋ณต์ฌํจ์ผ๋ก์จ ๋ฌธ์ ํด๊ฒฐ
public class HashTable implements Cloneable {
private Entry[] buckets = ...;
private static class Entry {
final Object key;
Object value;
Entry next;
Entry(Obejct 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]; // 1. ์ ์ ํ ํฌ๊ธฐ์ ์๋ก์ด ๋ฒํท ๋ฐฐ์ด ํ ๋น
for (int i = 0; i < buckets.length; i++) { // 2. ์๋์ ๋ฒํท ๋ฐฐ์ด์ ์ํํ๋ฉฐ
if (buckets[i] != null) { // ๋น์ง ์์ ๊ฐ ๋ฒํท์ ๋ํด ๊น์ ๋ณต์ฌ
result.buckets[i] = buckets[i].deepCopy();
}
}
return result;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
...
}
๐ ํ์ง๋ง ์์ ๊ฐ์ ์ฝ๋์์๋ ๋ฌธ์ ๊ฐ ์์ ! ์ฌ๊ท ํธ์ถ ๋๋ฌธ์ ๋ฆฌ์คํธ์ ์์ ์๋งํผ ์คํ ํ๋ ์์ ์๋นํ๋ฏ๋ก ๋ฆฌ์คํธ๊ฐ ๊ธธ๋ฉด StackOverFlow ๋ฐ์ํจ.
๊ทธ๋ฌ๋ฏ๋ก ์๋์ ๊ฐ์ด ์ฌ๊ทํธ์ถ ๋์ ๋ฐ๋ณต์๋ฅผ ์จ์ ์ํํ๋ ๋ฐฉํฅ์ผ๋ก ์์ ํด์ผ ํจ.
// ์ํธ๋ฆฌ ์์ ์ด ๊ฐ๋ฆฌํค๋ ์ฐ๊ฒฐ ๋ฆฌ์คํธ๋ฅผ ๋ฐ๋ณต์ ์ผ๋ก ๋ณต์ฌ
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์ ์ด๋ฏธ ๊ตฌํํ ํด๋์ค๋ฅผ ํ์ฅํ๋ค๋ฉด clone์ ์ ์๋ํ๋๋ก ๊ตฌํํด์ผํจ...
ํ์ง๋ง ๊ทธ๋ ์ง ์์ ์ํฉ์์๋ ๋ณต์ฌ ์์ฑ์์ ๋ณต์ฌ ํฉํ ๋ฆฌ๋ก ๋ ๋์ ๊ฐ์ฒด ๋ณต์ฌ ๋ฐฉ์์ ์ฌ์ฉํ๋ฉด ์ข๋ค !
โณ๏ธ ๋ณต์ฌ ์์ฑ์ (๋ณํ ์์ฑ์)
๐ ์์ ๊ณผ ๊ฐ์ ํด๋์ค์ ์ธ์คํด์ค๋ฅผ ์ธ์๋ก ๋ฐ๋ ์์ฑ์
public Yum(Yum yum) { ... };
โณ๏ธ ๋ณต์ฌ ํฉํ ๋ฆฌ (๋ณํ ํฉํ ๋ฆฌ)
๐ ๋ณต์ฌ ์์ฑ์๋ฅผ ๋ชจ๋ฐฉํ ์ ์ ํฉํ ๋ฆฌ
public static Yum newInstance(Yum yum) { ... };
๋ณต์ ๊ธฐ๋ฅ์ ์์ฑ์์ ํฉํ ๋ฆฌ๋ฅผ ์ด์ฉํ๋ ๊ฒ์ด ์ต๊ณ ๋ค..
๋จ, ๋ฐฐ์ด๋ง์ clone ๋ฉ์๋ ๋ฐฉ์์ด ๊ฐ์ฅ ๊น๋ํ๋ค!
14. Comparable ๊ตฌํํ ์ง ๊ณ ๋ ค
- Comparable ์ธํฐํ์ด์ค์ ๋ฉ์๋ = compareTo
- compareTo๋ ๋จ์ ๋์น์ฑ ๋น๊ต, ์์ ๋น๊ต
- ํ๋์ ๊ฐ ๋น๊ตํ ๋ < ์ > ์ฐ์ฐ์ ์ฌ์ฉ X
- ๋ฐ์ฑ๋ ๊ธฐ๋ณธ ํ์ ํด๋์ค๊ฐ ์ ๊ณตํ๋ ์ ์ compare ๋ฉ์๋๋ Comparator ์ธํฐํ์ด์ค๊ฐ ์ ๊ณตํ๋ ๋น๊ต์ ์์ฑ ๋ฉ์๋ ์ฌ์ฉ
- Comparable๋ฅผ ๊ตฌํํ์ = ๊ทธ ํด๋์ค์ ์ธ์คํด์ค๋ค์๋ ์์ฐ์ ์ธ ์์ ์์
public interface Comparable<T> {
int compareTo(T t);
}
โณ๏ธ compareTo ๋ฉ์๋์ ์ผ๋ฐ ๊ท์ฝ
- ๊ฐ์ฒด๊ฐ ์ฃผ์ด์ง ๊ฐ์ฒด๋ณด๋ค ์์ผ๋ฉด ์์ ์ ์๋ฅผ, ๊ฐ์ผ๋ฉด 0, ํฌ๋ฉด ์์ ์ ์ ๋ฐํ
- ๋น๊ตํ ์ ์๋ ํ์ ์ ๊ฐ์ฒด๊ฐ ์ฃผ์ด์ง๋ฉด ClassCastException ๋์ง
โด๏ธ ๊ธฐ๋ณธ ํ์ ํ๋๊ฐ ์ฌ๋ฟ์ผ ๋์ ๋น๊ต์
public int compareTo(PhoneNumber pn) {
int result = Short.compare(areaCode, pn.areaCode); // ๊ฐ์ฅ ์ค์ํ ํ๋
if (result == 0) {
result = Short.compare(prefix, pn.prefix); // ๋ ๋ฒ์งธ๋ก ์ค์ํ ํ๋
if (result == 0) {
result = Short.compare(lineNum, pn.lineNum); // ์ธ ๋ฒ์งธ๋ก ์ค์ํ ํ๋
}
return result;
}
๐ ๊ฐ์ฅ ํต์ฌ์ ์ธ ํ๋๋ถํฐ ๋น๊ตํด๋๊ฐ๊ธฐ (๋น๊ต๊ฒฐ๊ณผ๊ฐ 0์ด ์๋๋ผ๋ฉด, ์ฆ ์์๊ฐ ๊ฒฐ์ ๋๋ฉด ์ฌ๊ธฐ์ ๋๋๋ฏ๋ก ๋ฐ๋ก ๋ฐํ ๊ฐ๋ฅ)
โด๏ธ ๋น๊ต์ ์์ฑ ๋ฉ์๋๋ฅผ ํ์ฉํ ๋น๊ต์
private static final Comparator<PhoneNumber> COMPARATOR =
comparingInt((PhoneNumber pn) -> pn.areaCode)
.thenComparingInt(pn -> pn.prefix)
.thenComparingInt(pn -> pn.lineNum);
public int compareTo(PhoneNumber pn) {
return COMPARATOR.compare(this, pn);
}
โด๏ธ ์ ์ compare ๋ฉ์๋๋ฅผ ํ์ฉํ ๋น๊ต์
static Comparator<Object> hashCodeOrder = new Comparator<>() {
public int compare(Object o1, Object o2) {
return Integer.compare(o1.hashCode(), o2.hashCode());
}
}
โด๏ธ ๋น๊ต์ ์์ฑ ๋ฉ์๋๋ฅผ ํ์ฉํ ๋น๊ต์
static Comparator<Object> hasCodeOrder =
Comparator.comparingInt(o -> hashCode());
'Java > ๐ Effective Java' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[๐ Effective Java] ํด๋์ค์ ์ธํฐํ์ด์ค ไธญ (2) | 2024.10.05 |
---|---|
[๐ Effective Java] ํด๋์ค์ ์ธํฐํ์ด์ค ไธ (1) | 2024.09.25 |
[Effective Java] ๋ชจ๋ ๊ฐ์ฒด์ ๊ณตํต ๋ฉ์๋ ไธ (0) | 2024.09.21 |
[๐ Effective Java] ๊ฐ์ฒด ์์ฑ๊ณผ ํ๊ดด ไธ (0) | 2024.09.20 |
[๐ Effective Java] ๊ฐ์ฒด ์์ฑ๊ณผ ํ๊ดด ไธ (1) | 2024.09.16 |