2023. 2. 3. 11:42γJAVA/Effective JAVA
item13. clone μ¬μ μλ μ£Όμν΄μ μ§ννλΌ.
-> 첫λ²μ§Έ κ²μκΈμμλ clone κ·μ½μ λν΄μ λ΄€λλ° clone λ©μλμ κ·μ½μ μ½κ° νμ ν νΈμ΄λΌκ³ ν μμλ€.
x.clone() != x -> true
x.clone().getClass() == x.getClass() -> true
x.clone().equals(x) --> μΌλ°μ μΌλ‘ μ°Έμ΄μ§λ§ νμλ μλ
κ·Έλ¦¬κ³ λͺ¨λ νλκ° κΈ°λ³Έ νμ μ΄κ±°λ λΆλ³ κ°μ²΄λ₯Ό μ°Έμ‘°νλ€λ©΄ μ΄ κ°μ²΄λ Cloneable μΈν°νμ΄μ€λ₯Ό ꡬννκ³ , clone λ©μλλ₯Ό μ¬μ μνλ©΄ λλ€.
κ·Όλ° κ°λ³ κ°μ²΄μ κ²½μ°μλ λ§μ΄ λ¬λΌμ§λ€. μ¬κΈ°μλ μμ κ°μ΄λ§ ꡬνν΄μ£Όλ©΄ μλ³Έκ³Ό 볡μ¬λ³Έμ΄ κ°μ κ°μ²΄λ₯Ό μ°Έμ‘°νκ² λΌμ μλ³Έμ΄λ 볡μ λ³Έ μ€ νλλ₯Ό μμ νλ€λ©΄ λ€λ₯Έ νλλ μμ λμ΄ λΆλ³μμ ν΄μΉκ² λλ€.
-> λ°λΌμ κΉμ λ³΅μ¬ deep copyλ₯Ό ν΄μΌνλ€.
@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();
}
}
μ΄λ κ² clone λ©μλλ₯Ό μ μνκ³ λμ μ£Όμν μ μ μ¬μ μν μ μλ λ©μλλ₯Ό νΈμΆνμ§ μμμΌ νλ€λ μ μ΄λ€.
λ§μ½μ cloneμ΄ νμ ν΄λμ€μμ μ¬μ μν λ©μλλ₯Ό νΈμΆνλ©΄ νμ ν΄λμ€λ 볡μ κ³Όμ μμ μμ μ μνλ₯Ό κ΅μ ν κΈ°νλ₯Ό μκ² λμ΄ μλ³Έκ³Ό 볡μ λ³Έμ μνκ° λ¬λΌμ§ κ°λ₯μ±μ΄ ν¬λ€.
κ·Έλ¦¬κ³ μ£Όμν μ μΌλ‘λ μμν΄μ μ°κΈ° μν ν΄λμ€ μ€κ³ λ°©μ μ€ μ΄λμͺ½μμλ μμμ© ν΄λμ€λ Cloneable μ ꡬνν΄μλ μλλ€.
public abstract class Shape implements Cloneable { // μ§κΈμ κ΅³μ΄ μ¬μ©ν κ²½μ°
private int area;
public abstract int getArea();
}
μ§κΈμ Cloneable μ κ΅³μ΄ κ΅¬νν κ²½μ°μΈλ° μ΄λ κ² λλ©΄ Objectλ₯Ό λ°λ‘ μμν λ μ²λΌ Cloneable ꡬν μ¬λΆλ₯Ό νμν΄λμ€μμ μ ννλλ‘ ν΄ ν΄λΉ ν΄λμ€λ₯Ό νμ₯νλ νλ‘κ·Έλλ¨Έμκ² λ§μ λΆλ΄μ μ€λ€.
μ΄λ΄λ ν΄κ²° λ°©λ²μΌλ‘λ
/**
* λ°©λ² 1) νλ‘κ·Έλλ¨Έμκ² λΆλ΄μ λκΈ° μν΄μλ κΈ°λ³Έ clone() ꡬν체λ₯Ό μ 곡νκ³ ,
* Cloneable ꡬν μ¬λΆλ₯Ό μλΈ ν΄λμ€μμ μ νν μ μλλ‘ νλ€.
* μλΈ ν΄λμ€κ° ꡬνμ μν΄λ λλλ‘
* @return
* @throws CloneNotSupportedException
*/
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
clone λ©μλλ₯Ό μμ ν΄λμ€μμ 미리 ꡬνμ νκ³ , νμ ν΄λμ€μμ ꡬνμ μν΄λ λλλ‘ μ 곡ν΄μ£Όλ λ°©λ²μ΄λ€.
/**
* λ°©λ² 2) Cloneable ꡬνμ μμ λ§λ λ°©λ²
* @return
* @throws CloneNotSupportedException
*/
@Override
protected final Object clone() throws CloneNotSupportedException {
return new CloneNotSupportedException();
}
λλ cloneμ λμνμ§ μκ² κ΅¬νν΄λκ³ νμ ν΄λμ€μμ μ¬μ μνμ§ λͺ»νκ² ν μλ μλ€.
public class Square extends Shape
{
private int length, height;
public Square(int length, int height)
{
this.length = length;
this.height = height;
}
@Override
public int getArea()
{
return this.length * this.height;
}
public static void main(String[] args) throws CloneNotSupportedException
{
Square square = new Square(10, 2);
Square clone = (Square) square.clone();
System.out.println("clone.getArea() = " + clone.getArea());
}
}
μ΄λ κ² νλ©΄ νμ ν΄λμ€μμλ cloneμ ꡬννμ§ μμλ λλ€.
κ·Έλ¦¬κ³ λ μ£Όμ?ν΄μΌν μ μ Cloneable μ ꡬνν μ°λ λ μμ ν΄λμ€λ₯Ό μμ±ν λλ clone λ©μλ μμ μ μ νκ² λκΈ°ν ν΄μ€μΌ νλ€.
@Override
public synchronized HashTable clone() { // λ©ν°μ°λ λ νκ²½μμ μμ ν΄μΌ νλ€λ©΄ synchronizedκΉμ§ λΆμ¬μ€μΌν¨
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();
}
}
π μ 리
μ 리νμλ©΄, Cloneable μ ꡬννλ λͺ¨λ ν΄λμ€λ cloneμ μ¬μ μν΄μΌ νκ³ , μ΄λ μ κ·Ό μ νμλ publicμΌλ‘, λ°ν νμ μ ν΄λμ€ μμ μΌλ‘ λ³κ²½ν΄μ£Όλ©΄ λλ€.
κ·Έ λ€μ super.clone()μ νΈμΆν ν νμν νλλ₯Ό λͺ¨λ μ μ ν μμ ν΄μ£Όλ©΄ λλ€. (κΉμ 볡μ¬λ‘ λͺ¨λ κ°λ³ κ°μ²΄λ₯Ό 볡μ¬νκ³ , 볡μ λ³Έμ΄ κ°μ§ κ°μ²΄ μ°Έμ‘° λͺ¨λ 볡μ¬λ κ°μ²΄λ€μ κ°λ¦¬ν€κ² νλ©΄ λλ€.)
Cloneableμ μ΄λ―Έ ꡬνν ν΄λμ€λ₯Ό νμ₯νλ€λ©΄ cloneμ μ μλνλλ‘ κ΅¬νν΄μΌ νμ§λ§, κ·Έλ μ§ μμ μν©μ΄λΌλ©΄ λ³΅μ¬ μμ±μμ λ³΅μ¬ ν©ν°λ¦¬λΌλ λ λμ κ°μ²΄ λ³΅μ¬ λ°©μμ μ 곡ν μ μλ€.
-> λ³΅μ¬ μμ±μλ λ¨μν μμ κ³Ό κ°μ ν΄λμ€μ μΈμ€ν΄μ€λ₯Ό μΈμλ‘ λ°λ μμ±μλ₯Ό λ§νλ€.
/**
* clone λμ - copy μμ±μλ₯Ό λ§λλ λ°©λ²
* @param phoneNumber
*/
public PhoneNumber(PhoneNumber phoneNumber)
{
this(phoneNumber.areaCode, phoneNumber.prefix, phoneNumber.lineNum);
}
μ΄λ°μμΌλ‘ λ³΅μ¬ μμ±μλ μ΄μ λ³νμΈ λ³΅μ¬ ν©ν°λ¦¬λ Cloneable/ clone λ°©μλ³΄λ€ λ λμ μ μ΄ λ§λ€.
μΌλ¨ μΈμ΄ λͺ¨μμ μ΄κ³ μνμ²λ§ν κ°μ²΄ μμ± λ©μ»€λμ¦(μμ±μλ₯Ό μ°μ§ μλ λ°©μ)μ μ¬μ©νμ§ μμΌλ©°, μμ±νκ² λ¬Έμνλ κ·μ½μ κΈ°λμ§ μκ³ , μ μμ μΈ final νλ μ©λ²κ³Όλ μΆ©λνμ§ μμΌλ©΄μ λΆνμν κ²μ¬ μμΈλ₯Ό λμ§μ§ μκ³ , νλ³νλ νμνμ§ μλ€.
public static void main(String[] args)
{
Set<String> hashSet = new HashSet<>();
hashSet.add("hyejin");
hashSet.add("clone");
System.out.println("hashSet = " + hashSet);
Set<String> treeSet = new TreeSet<>(hashSet);
System.out.println("treeSet = " + treeSet);
}
κ·Έλ¦¬κ³ λ³΅μ¬ μμ±μμ λ³΅μ¬ ν©ν°λ¦¬λ ν΄λΉ ν΄λμ€κ° ꡬνν 'μΈν°νμ΄μ€' νμ μΌλ‘ μΈμ€ν΄μ€λ₯Ό μΈμλ‘ λ°μ μ μλ€.
κ΄λ‘μ λͺ¨λ λ²μ© 컬λ μ ꡬν체λ Collectionμ΄λ Map νμ μ λ°λ μμ±μλ₯Ό μ 곡νλ€.
μ΄λ₯Ό μ΄μ©νλ©΄ ν΄λΌμ΄μΈνΈλ μλ³Έμ ꡬν νμ μ μ½λ§€μ΄μ§ μμΌλ©΄μλ 볡μ λ³Έμ νμ μ μ μ νκ² μ νν μ μλ€.
μμ μμμ²λΌ HashSet κ°μ²΄λ₯Ό TreeSet νμ μΌλ‘ 볡μ ν μ μλ€.
π©π» κ²°λ‘ μ λ§νμλ©΄? Cloneableμ μ§κΈκΉμ§ λ΄μ¨κ±Έ μκ°ν΄λ³΄λ©΄ μ£Όμν μ λ λ§κ³ , μ 맀λͺ¨νΈν μ λ μκ³ ν΄μ Cloneableμ νμ₯ν΄μλ μλκ³ , μλ‘μ΄ ν΄λμ€λ μ΄λ₯Ό ꡬννλ κ²λ³΄λ€λ λ³΅μ¬ μμ±μλ λ³΅μ¬ ν©ν°λ¦¬λ₯Ό νμ©νλ κ²μ΄ λ λ«λ€.