[μ΄νŽ™ν‹°λΈŒ μžλ°”] Item13. clone μž¬μ •μ˜λŠ” μ£Όμ˜ν•΄μ„œ μ§„ν–‰ν•˜λΌ. (clone λŒ€μ•ˆ)

2023. 2. 3. 11:42ㆍJAVA/Effective JAVA

728x90

 

item13. clone μž¬μ •μ˜λŠ” μ£Όμ˜ν•΄μ„œ μ§„ν–‰ν•˜λΌ. 

[μ΄νŽ™ν‹°λΈŒ μžλ°”] Item13. clone μž¬μ •μ˜λŠ” μ£Όμ˜ν•΄μ„œ μ§„ν–‰ν•˜λΌ. (Cloneκ·œμ•½) (tistory.com)

 

[μ΄νŽ™ν‹°λΈŒ μžλ°”] Item13. clone μž¬μ •μ˜λŠ” μ£Όμ˜ν•΄μ„œ μ§„ν–‰ν•˜λΌ. (Cloneκ·œμ•½)

item13. clone μž¬μ •μ˜λŠ” μ£Όμ˜ν•΄μ„œ μ§„ν–‰ν•˜λΌ. Clone() μ΄λž€? : Object 클래슀의 clone() λ©”μ„œλ“œλŠ” μžμ‹ μ„ λ³΅μ œν•˜μ—¬ μƒˆλ‘œμš΄ μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜λŠ” 일을 ν•œλ‹€. λ‹¨μˆœνžˆ μΈμŠ€ν„΄μŠ€ λ³€μˆ˜μ˜ κ°’λ§Œ λ³΅μ‚¬ν•˜κΈ° λ•Œλ¬Έμ— μ°Έ

hyejin.tistory.com

-> 첫번째 κ²Œμ‹œκΈ€μ—μ„œλŠ”  clone κ·œμ•½μ— λŒ€ν•΄μ„œ λ΄€λŠ”λ° clone λ©”μ„œλ“œμ˜ κ·œμ•½μ€ μ•½κ°„ ν—ˆμˆ ν•œ 편이라고 ν•  μˆ˜μžˆλ‹€. 

x.clone() != x  -> true 
x.clone().getClass() == x.getClass() -> true 
x.clone().equals(x) --> 일반적으둠 μ°Έμ΄μ§€λ§Œ ν•„μˆ˜λŠ” μ•„λ‹˜ 

그리고 λͺ¨λ“  ν•„λ“œκ°€ κΈ°λ³Έ νƒ€μž…μ΄κ±°λ‚˜ λΆˆλ³€ 객체λ₯Ό μ°Έμ‘°ν•œλ‹€λ©΄ 이 κ°μ²΄λŠ” Cloneable μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜κ³ , clone λ©”μ„œλ“œλ₯Ό μž¬μ •μ˜ν•˜λ©΄ λœλ‹€. 

 

[μ΄νŽ™ν‹°λΈŒ μžλ°”] Item13. clone μž¬μ •μ˜λŠ” μ£Όμ˜ν•΄μ„œ μ§„ν–‰ν•˜λΌ. (κ°€λ³€ 객체 clone μ •μ˜ν•˜λŠ” 방법) (tistory.com)

 

[μ΄νŽ™ν‹°λΈŒ μžλ°”] Item13. clone μž¬μ •μ˜λŠ” μ£Όμ˜ν•΄μ„œ μ§„ν–‰ν•˜λΌ. (κ°€λ³€ 객체 clone μ •μ˜ν•˜λŠ” 방법)

item13. clone μž¬μ •μ˜λŠ” μ£Όμ˜ν•΄μ„œ μ§„ν–‰ν•˜λΌ. https://hyejin.tistory.com/1039 [μ΄νŽ™ν‹°λΈŒ μžλ°”] Item13. clone μž¬μ •μ˜λŠ” μ£Όμ˜ν•΄μ„œ μ§„ν–‰ν•˜λΌ. (Cloneκ·œμ•½) item13. clone μž¬μ •μ˜λŠ” μ£Όμ˜ν•΄μ„œ μ§„ν–‰ν•˜λΌ. Clone() μ΄λž€? : Object

hyejin.tistory.com

근데 κ°€λ³€ 객체에 κ²½μš°μ—λŠ” 말이 달라진닀. μ—¬κΈ°μ„œλŠ” μœ„μ™€ κ°™μ΄λ§Œ κ΅¬ν˜„ν•΄μ£Όλ©΄ 원본과 볡사본이 같은 객체λ₯Ό μ°Έμ‘°ν•˜κ²Œ λΌμ„œ μ›λ³Έμ΄λ‚˜ 볡제본 쀑 ν•˜λ‚˜λ₯Ό μˆ˜μ •ν•œλ‹€λ©΄ λ‹€λ₯Έ ν•˜λ‚˜λ„ μˆ˜μ •λ˜μ–΄ λΆˆλ³€μ‹μ„ ν•΄μΉ˜κ²Œ λœλ‹€. 

-> λ”°λΌμ„œ κΉŠμ€ 볡사 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을 ν™•μž₯ν•΄μ„œλŠ” μ•ˆλ˜κ³ , μƒˆλ‘œμš΄ ν΄λž˜μŠ€λ„ 이λ₯Ό κ΅¬ν˜„ν•˜λŠ” κ²ƒλ³΄λ‹€λŠ” 볡사 μƒμ„±μžλ‚˜ 볡사 νŒ©ν„°λ¦¬λ₯Ό ν—ˆμš©ν•˜λŠ” 것이 더 λ‚«λ‹€. 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90