Skip to content

Latest commit

Β 

History

History
728 lines (527 loc) Β· 29.9 KB

File metadata and controls

728 lines (527 loc) Β· 29.9 KB
description
이번 μ•„μ΄ν…œμ€ clone()을 μ‚¬μš©ν•  λ•Œ μ£Όμ˜μ μ„ 닀룬닀.

item 13 : clone μž¬μ •μ˜λŠ” μ£Όμ˜ν•΄μ„œ 진행해라

1. Cloneable μΈν„°νŽ˜μ΄μŠ€

Cloneaable μΈν„°νŽ˜μ΄μŠ€λž€?

  • μΌμ’…μ˜ maker interface둜 'cloen에 μ˜ν•΄ λ³΅μ œν•  수 μžˆλ‹€'λ₯Ό ν‘œμ‹œν•˜λŠ” μΈν„°νŽ˜μ΄μŠ€μ΄λ‹€.
  • λ³΅μ œν•΄λ„ λ˜λŠ” ν΄λž˜μŠ€μž„μ„ λͺ…μ‹œν•˜λŠ” μš©λ„μ˜ 믹슀인 μΈν„°νŽ˜μ΄μŠ€

Javaμ—μ„œλŠ” μΈμŠ€ν„΄μŠ€μ˜ 볡제λ₯Ό μœ„ν•΄ clone() λ©”μ„œλ“œκ°€ κ΅¬ν˜„λ˜μ–΄ μžˆλ‹€.

μ‹ κΈ°ν•˜κ²Œλ„ 이 λ©”μ„œλ“œλŠ” Cloneable 내뢀에 κ΅¬ν˜„λ˜μ–΄ μžˆμ„ κ±°λž€ μ˜ˆμƒμ„ κΉ¨κ³  java.lang.Object ν΄λž˜μŠ€μ— protected μ ‘κ·Ό μ§€μ •μžλ‘œ κ΅¬ν˜„λ˜μ–΄ μžˆλ‹€. λ‚΄λΆ€μ—λŠ” κ΅¬ν˜„ν•΄μ•Ό ν•  λ©”μ„œλ“œκ°€ ν•˜λ‚˜λ„ μ—†λ‹€!

Cloneaable μΈν„°νŽ˜μ΄μŠ€ ν•˜λŠ” 일

  • Object의 protected λ©”μ„œλ“œμΈ clone의 λ™μž‘ 방식을 κ²°μ •ν•œλ‹€.
  • Cloneable의 경우, 일반적으둜 μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•œλ‹€λŠ” 것 즉, ν•΄λ‹Ή ν΄λž˜μŠ€κ°€ κ·Έ μΈν„°νŽ˜μ΄μŠ€μ—μ„œ μ •μ˜ν•œ κΈ°λŠ₯을 μ œκ³΅ν•œλ‹€κ³  μ„ μ–Έν•˜λŠ” 것과 달리 μƒμœ„ ν΄λž˜μŠ€μ— μ •μ˜λœ protected λ©”μ„œλ“œμ˜ λ™μž‘λ°©μ‹μ„ λ³€κ²½ν•œ 것

μ‚¬μš©λ²•

public class Pokemon implements Cloneable {
    private List<String> skills;
    private int attack;
    private int defense;
    private int hp;

    public Pokemon(List<String> skills, int attack, int defense, int hp) {
        this.skills = skills;
        this.attack = attack;
        this.defense = defense;
        this.hp = hp;
    }

    @Override // clone() κ΅¬ν˜„..!!
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    // getter, seterr ...
}

볡사할 객체에 Cloneable을 μƒμ†μ‹œμΌœ μ€€ λ’€ μ˜€λ²„λΌμ΄λ”©ν•΄ μ£Όλ©΄ λœλ‹€.

clone()을 ν˜ΈμΆœν•˜λ©΄ μΈμŠ€ν„΄μŠ€μ™€ 같은 크기의 λ©”λͺ¨λ¦¬λ₯Ό ν• λ‹Ήν•˜κ³ , μΈμŠ€ν„΄μŠ€μ˜ ν•„λ“œλ₯Ό κ·ΈλŒ€λ‘œ λ³΅μ‚¬ν•œ 볡사본을 λ¦¬ν„΄ν•œλ‹€.

Clonable μΈν„°νŽ˜μ΄μŠ€μ˜ 문제점

  1. λ³΅μž‘μ„±κ³Ό μœ„ν—˜μ„±
  • Cloneableκ³Ό clone() λ©”μ„œλ“œλŠ” 객체 볡사 λ©”μ»€λ‹ˆμ¦˜μ΄ 직관적이지 μ•Šκ³ , 잘λͺ» κ΅¬ν˜„ν•˜λ©΄ 였λ₯˜κ°€ λ°œμƒν•˜κΈ° 쉽닀.
  • κ°€λ³€ 객체의 볡사, final ν•„λ“œμ™€μ˜ 좩돌, μ˜ˆμ™Έ 처리 λ“± μ—¬λŸ¬ 가지 λ¬Έμ œκ°€ μžˆλ‹€.

2. 재 μ •μ˜μ‹œ 문제점

πŸ€” Cloneable을 κ΅¬ν˜„ν•œ ν΄λž˜μŠ€λŠ” clone λ©”μ„œλ“œλ₯Ό public으둜 μ œκ³΅ν•˜λ©°, μ‚¬μš©μžλŠ” λ‹Ήμ—°νžˆ λ³΅μ œκ°€ μ œλŒ€λ‘œ 이뀄지겠지? 라고 μ‹€λ¬΄μ—μ„œλŠ” κΈ°λŒ€

이 κΈ°λŒ€λ₯Ό λ§Œμ‘±μ‹œν‚€λ €λ©΄ κ·Έ ν΄λž˜μŠ€μ™€ λͺ¨λ“  μƒμœ„ ν΄λž˜μŠ€λŠ” 볡작 ν•˜κ³ , κ°•μ œν•  수 μ—†κ³ , ν—ˆμˆ ν•˜κ²Œ 기술된 ν”„λ‘œν† μ½œμ„ μ§€μΌœμ•Όλ§Œ ν•˜λŠ”λ°, κ·Έ κ²°κ³Ό 둜 깨지기 쉽고, μœ„ν—˜ν•˜κ³ , λͺ¨μˆœμ μΈ λ©”μ»€λ‹ˆμ¦˜μ΄ νƒ„μƒν•œλ‹€. μƒμ„±μžλ₯Ό ν˜ΈμΆœν•˜μ§€ μ•Šκ³ λ„ 객체λ₯Ό 생성할 수 있게 λ˜λŠ” 것이닀.

3. Clone() λ©”μ„œλ“œ

1) clone() λ©”μ„œλ“œμ˜ 일반 κ·œμ•½

μ•½κ°„ ν—ˆμˆ ν•˜λ‹€κ³  함

  1. x.clone() ! =x 식은 참이어야 ν•œλ‹€.
  • λ³΅μ‚¬λœ 객체와 μ›λ³Έμ΄λž‘ 같은 μ£Όμ†Œλ₯Ό 가지면 μ•ˆλœλ‹€λŠ” 뜻
  1. x.clone().getClass() == x.getClass() 식도 참이어야 ν•œλ‹€.
  • λ³΅μ‚¬λœ 객체가 같은 ν΄λž˜μŠ€μ—¬μ•Ό ν•œλ‹€λŠ” μ†Œλ¦¬μž„
  1. x.clone().equals(x) 참이어야 ν•˜μ§€λ§Œ ν•„μˆ˜λŠ” μ•„λ‹ˆλ‹€.
  • λ³΅μ‚¬λœ 객체가 논리적 λ™μΉ˜λŠ” μΌμΉ˜ν•΄μ•Ό ν•œλ‹€κ³  함

λ°˜ν™˜λœ 객체와 원본 κ°μ²΄λŠ” 독립적이어야 ν•œλ‹€. 이λ₯Ό λ§Œμ‘±ν•˜λ €λ©΄ super.clone으둜 얻은 객체의 ν•„λ“œ 쀑 ν•˜λ‚˜ 이상을 λ°˜ν™˜ 전에 μˆ˜μ •ν•΄μ•Ό ν•  μˆ˜λ„ μžˆλ‹€.

2) super.clone()의 μ€‘μš”μ„±

super.clone()을 ν˜ΈμΆœν•΄μ•Ό ν•˜λŠ” 이유

clone() λ©”μ„œλ“œλ₯Ό μž¬μ •μ˜ν•  λ•Œ κ°€μž₯ λ¨Όμ € ν•΄μ•Ό ν•  일은 super.clone()을 ν˜ΈμΆœν•˜λŠ” 것이닀. μ΄λŠ” Object 클래슀의 clone() λ©”μ„œλ“œλ₯Ό 톡해 객체의 ν•„λ“œ 값을 λ³΅μ‚¬ν•œ μƒˆλ‘œμš΄ 객체λ₯Ό μƒμ„±ν•˜κΈ° μœ„ν•¨μ΄λ‹€.

@Override
public Object clone() throws CloneNotSupportedException {
    return super.clone();
}

ν•˜μœ„ ν΄λž˜μŠ€μ—μ„œμ˜ 문제점

λ§Œμ•½ super.clone()을 ν˜ΈμΆœν•˜μ§€ μ•Šκ³  μƒμ„±μžλ₯Ό μ‚¬μš©ν•˜μ—¬ μΈμŠ€ν„΄μŠ€λ₯Ό λ°˜ν™˜ν•œλ‹€λ©΄, ν•˜μœ„ ν΄λž˜μŠ€μ—μ„œ super.clone()을 ν˜ΈμΆœν•  λ•Œ μ˜¬λ°”λ₯Έ 클래슀의 객체가 μƒμ„±λ˜μ§€ μ•Šμ„ 수 μžˆλ‹€. μ΄λŠ” ν•˜μœ„ 클래슀의 clone() λ©”μ„œλ“œκ°€ μ œλŒ€λ‘œ λ™μž‘ν•˜μ§€ μ•Šκ²Œ λ§Œλ“€ 수 μžˆλ‹€.

  • μ˜ˆμ‹œ: μƒμœ„ ν΄λž˜μŠ€μ—μ„œ super.clone()을 ν˜ΈμΆœν•˜μ§€ μ•Šκ³  μƒˆλ‘œμš΄ 객체λ₯Ό μƒμ„±ν•˜λ©΄, ν•˜μœ„ ν΄λž˜μŠ€μ—μ„œ super.clone()을 ν˜ΈμΆœν•΄λ„ μƒμœ„ 클래슀의 μΈμŠ€ν„΄μŠ€κ°€ λ°˜ν™˜λ˜μ–΄ ν•˜μœ„ 클래슀의 ν•„λ“œκ°€ μ΄ˆκΈ°ν™”λ˜μ§€ μ•Šμ„ 수 μžˆλ‹€.

final 클래슀의 경우

ν΄λž˜μŠ€κ°€ final이라면 ν•˜μœ„ ν΄λž˜μŠ€κ°€ μ—†μœΌλ―€λ‘œ 이 κ·œμΉ™μ„ λ¬΄μ‹œν•΄λ„ μ•ˆμ „ν•˜λ‹€. κ·ΈλŸ¬λ‚˜ 이 κ²½μš°μ—λ„ Cloneable을 κ΅¬ν˜„ν•  ν•„μš”κ°€ μ—†λ‹€. Object의 clone() λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ΄λ‹€.

3. Clone() λ©”μ„œλ“œμ˜ κ΅¬ν˜„

1) κ°€λ³€ μƒνƒœλ₯Ό μ°Έμ‘°ν•˜μ§€ μ•ŠλŠ” 클래슀용 clone() λ©”μ„œλ“œ

  1. super.clone()을 ν˜ΈμΆœν•œλ‹€.
  • μ •μ˜λœ λͺ¨λ“  ν•„λ“œλŠ” 원본 ν•„λ“œμ™€ λ˜‘κ°™μ€ 값을 κ°–κ²Œ λœλ‹€.
  • λͺ¨λ“  ν•„λ“œκ°€ primitive νƒ€μž…μ΄κ±°λ‚˜ final 이라면, 이 μƒνƒœλ‘œ 끝이닀.
  • 사싀 final은 쓸데 μ—†λŠ” 볡사λ₯Ό μ§€μ–‘ν•˜κΈ° λ•Œλ¬Έμ— clone()이 ν•„μš” μ—†λ‹€.
@Override
public PhoneNumber clone() {
    try {
        return (PhoneNumber) super.clone();
    } catch (CloneNotSupportedException e) {
        throw new AssertionError(); // 일어날 수 μ—†λŠ” 일이닀.
    }
}
  • PhoneNumber νƒ€μž…μœΌλ‘œ ν˜•λ³€ν™˜ν•˜μ—¬ λ°˜ν™˜ν•˜λ„λ‘ ν•΄μ„œ νŽΈμ˜μ„±μ„ μ¦λŒ€μ‹œμΌ°λ‹€.
  • try-catch λΈ”λ‘μœΌλ‘œ 감싼 μ΄μœ λŠ” Object.clone() λ©”μ„œλ“œκ°€ CloneNotSupportedException을 λ˜μ§€κΈ° λ•Œλ¬Έμ΄λ‹€.

우린 PhoneNumber ν΄λž˜μŠ€κ°€ Cloneable μΈν„°νŽ˜μ΄μŠ€λ₯Ό μƒμ†λ°›λŠ” 것을 보고 clone()을 지원함을 μ•Œ 수 μžˆλ‹€.

CloneNotSupportedException μ˜ˆμ™Έ 처리

  • Object의 clone() λ©”μ„œλ“œλŠ” CloneNotSupportedException을 λ‹€.
  • Cloneable을 κ΅¬ν˜„ν•œ ν΄λž˜μŠ€μ—μ„œ clone() λ©”μ„œλ“œλ₯Ό μž¬μ •μ˜ν•  λ•ŒλŠ” 이 μ˜ˆμ™Έλ₯Ό 던질 ν•„μš”κ°€ μ—†μŠ΅λ‹ˆλ‹€.
  • λŒ€μ‹  try-catch λΈ”λ‘μœΌλ‘œ 감싸고, μ˜ˆμ™Έκ°€ λ°œμƒν•  수 μ—†μŒμ„ 보μž₯ν•˜κΈ° μœ„ν•΄ AssertionError1λ₯Ό λ˜μ§„λ‹€.
  • κ³Όλ„ν•œ 검사 μ˜ˆμ™ΈλŠ” APIλ₯Ό μ‚¬μš©ν•˜κΈ° λΆˆνŽΈν•˜κ²Œ λ§Œλ“ λ‹€.

2) κ°€λ³€ 객체λ₯Ό μ°Έμ‘°ν•˜λŠ” 클래슀의 clone() λ©”μ„œλ“œ κ΅¬ν˜„

{% hint style="info" %} κ°€λ³€κ°μ²΄λž€, instance 생성 이후에도 λ‚΄λΆ€ μƒνƒœ 변경이 κ°€λŠ₯ν•œ 객체λ₯Ό λ§ν•œλ‹€. {% endhint %}

  • 이 클래슀λ₯Ό κ·ΈλŒ€λ‘œ λ³΅μ œν•˜λ©΄, primitive νƒ€μž…μ˜ 값은 μ˜¬λ°”λ₯΄κ²Œ λ³΅μ œλ˜μ§€λ§Œ, 볡제된 Stack의 elementsλŠ” 볡제 μ „μ˜ Stackκ³Ό 같은 배열을 κ°€λ¦¬ν‚€κ²Œ 될 것이닀.
  • 두 μŠ€νƒμ— 같은 elementsκ°€ λ“€μ–΄μžˆκ³ , ν•˜λ‚˜λ₯Ό λ°”κΎΈλ©΄ λ‹€λ₯Έ ν•˜λ‚˜λ„ μ—°λ™λœλ‹€λŠ” λœ»μ΄λ‹€. 이건 μš°λ¦¬κ°€ μ›ν•œ clone()이 μ•„λ‹ˆλ‹€.
  • 예λ₯Ό λ“€μ–΄, Stack 클래슀의 elements 배열이 이에 ν•΄λ‹Ήν•œλ‹€.
  • Stack 클래슀의 μœ μΌν•œ μƒμ„±μžλ₯Ό μ΄μš©ν•˜λ©΄ 이런 λ¬Έμ œλŠ” 없을 것이닀. κ·ΈλŸ¬λ‚˜ 값이 λ³΅μ‚¬λ˜μ§€ μ•ŠλŠ” λ¬Έμ œκ°€ μžˆλ‹€.

얕은 λ³΅μ‚¬μ˜ 문제점

  • λ‹¨μˆœνžˆ super.clone()을 ν˜ΈμΆœν•˜λ©΄ 얕은 볡사가 이루어져, 객체의 ν•„λ“œ κ°’λ§Œ λ³΅μ‚¬λ˜κ³  κ·Έ ν•„λ“œλ“€μ΄ μ°Έμ‘°ν•˜λŠ” 객체듀은 λ³΅μ‚¬λ˜μ§€ μ•ŠλŠ”λ‹€.
  • λ”°λΌμ„œ κ°€λ³€ 객체λ₯Ό μ°Έμ‘°ν•˜λŠ” ν•„λ“œκ°€ μžˆμ„ 경우, 원본 객체와 볡제된 객체가 λ™μΌν•œ κ°€λ³€ 객체λ₯Ό κ³΅μœ ν•˜κ²Œ λœλ‹€.
  • 문제점: μ›λ³Έμ΄λ‚˜ 볡제본 쀑 ν•˜λ‚˜μ—μ„œ κ°€λ³€ 객체λ₯Ό λ³€κ²½ν•˜λ©΄ λ‹€λ₯Έ ν•˜λ‚˜μ—λ„ 영ν–₯을 미쳐 λΆˆλ³€μ‹μ΄ 깨질 수 μžˆλ‹€.

κΉŠμ€ λ³΅μ‚¬μ˜ ν•„μš”μ„±

원본과 볡제본이 독립적인 객체 μƒνƒœλ₯Ό μœ μ§€ν•˜λ €λ©΄ κ°€λ³€ 객체λ₯Ό 볡사해야 ν•œλ‹€. 이λ₯Ό μœ„ν•΄ ν•΄λ‹Ή ν•„λ“œλ₯Ό κΉŠμ€ λ³΅μ‚¬ν•˜μ—¬ μƒˆλ‘œμš΄ 객체λ₯Ό 생성해야 ν•œλ‹€.


3) κΉŠμ€ 볡사λ₯Ό μœ„ν•œ 방법

λ°°μ—΄μ˜ clone() λ©”μ„œλ“œ μ‚¬μš©

배열은 clone() λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ κΉŠμ€ 볡사가 μ΄λ£¨μ–΄μ§‘λ‹ˆλ‹€. 즉, λ°°μ—΄ μžμ²΄κ°€ λ³΅μ‚¬λ˜κ³  λ°°μ—΄μ˜ 각 μš”μ†Œλ“€λ„ λ³΅μ‚¬λ©λ‹ˆλ‹€. λ”°λΌμ„œ 배열을 λ³΅μ œν•  λ•ŒλŠ” λ°°μ—΄μ˜ clone() λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

  • μ˜ˆμ‹œ:
@Override
public Stack clone() {
    try {
        // λ¨Όμ € super.clone()을 ν˜ΈμΆœν•˜μ—¬ 이 객체의 얕은 볡사(shallow copy)λ₯Ό μˆ˜ν–‰ν•©λ‹ˆλ‹€.
        Stack result = (Stack) super.clone();

        // elements 배열을 λ³΅μ œν•˜μ—¬ 원본과 볡제본이 μ„œλ‘œ λ‹€λ₯Έ 배열을 μ°Έμ‘°ν•˜λ„λ‘ ν•©λ‹ˆλ‹€.
        result.elements = elements.clone();

        // 볡제된 Stack 객체λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.
        return result;

    } catch (CloneNotSupportedException e) {
        // 이 μ˜ˆμ™ΈλŠ” λ°œμƒν•˜μ§€ μ•ŠμœΌλ―€λ‘œ AssertionErrorλ₯Ό λ˜μ§‘λ‹ˆλ‹€.
        // Cloneable을 κ΅¬ν˜„ν–ˆκΈ° λ•Œλ¬Έμ— super.clone()은 성곡해야 ν•©λ‹ˆλ‹€.
        throw new AssertionError();
    }
}

🧐 μ™œ elements 배열을 λ³΅μ œν•˜λ‚˜μš”?

  • elements 배열은 Stack의 λ‚΄λΆ€ μƒνƒœλ₯Ό μ €μž₯ν•˜λŠ” μ€‘μš”ν•œ κ°€λ³€ 객체이닀.
  • 원본과 볡제본이 같은 배열을 κ³΅μœ ν•˜λ©΄ ν•œμͺ½μ—μ„œ 변경이 λ°œμƒν•  λ•Œ λ‹€λ₯Έ μͺ½μ—λ„ 영ν–₯을 λ―ΈμΉœλ‹€.
  • 이λ₯Ό λ°©μ§€ν•˜κΈ° μœ„ν•΄ elements 배열을 λ³΅μ œν•˜μ—¬ 볡제본이 독립적인 배열을 가지도둝 ν•œλ‹€.

μ‚¬μš©μ˜ˆμ œ

public class Stack implements Cloneable {
    private Object[] elements;
    private int size = 0;

    private static final int DEFAULT_INITIAL_CAPACITY = 16;

    // μƒμ„±μž
    public Stack() {
        elements = new Object[DEFAULT_INITIAL_CAPACITY];
    }

    // push λ©”μ„œλ“œ
    public void push(Object e) {
        ensureCapacity();
        elements[size++] = e;
    }

    // pop λ©”μ„œλ“œ
    public Object pop() {
        if (size == 0)
            throw new EmptyStackException();
        Object result = elements[--size];
        elements[size] = null; // λ‹€ μ“΄ μ°Έμ‘° ν•΄μ œ
        return result;
    }

    // λ‚΄λΆ€ λ°°μ—΄μ˜ 크기 μ‘°μ •
    private void ensureCapacity() {
        if (elements.length == size)
            elements = Arrays.copyOf(elements, 2 * size + 1);
    }

    // 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 Main {
    public static void main(String[] args) {
        Stack originalStack = new Stack();
        originalStack.push("A");
        originalStack.push("B");

        // μŠ€νƒ 볡제
        Stack clonedStack = originalStack.clone();

        // 원본 μŠ€νƒκ³Ό 볡제본 μŠ€νƒμ΄ λ³„κ°œμ˜ 객체인지 확인
        System.out.println(originalStack != clonedStack); // true

        // elements 배열이 λ³„κ°œμ˜ 객체인지 확인
        System.out.println(originalStack.elements != clonedStack.elements); // true

        // 원본과 볡제본의 λ‚΄μš©μ΄ 같은지 확인
        System.out.println(Arrays.equals(originalStack.elements, clonedStack.elements)); // true

        // 원본 μŠ€νƒμ— μΆ”κ°€
        originalStack.push("C");

        // λ³΅μ œλ³Έμ—λŠ” 영ν–₯이 μ—†λŠ”μ§€ 확인
        System.out.println(clonedStack.size); // 2
    }
}
  • μ„€λͺ…:
    • originalStack을 μƒμ„±ν•˜κ³  "A", "B"λ₯Ό μΆ”κ°€
    • originalStack을 λ³΅μ œν•˜μ—¬ clonedStack을 생성
    • 원본과 볡제본이 μ„œλ‘œ λ‹€λ₯Έ 객체이고, λ‚΄λΆ€μ˜ elements 배열도 λ‹€λ₯Έ κ°μ²΄μž„μ„ 확인
    • 원본 μŠ€νƒμ— "C"λ₯Ό 좔가해도 λ³΅μ œλ³Έμ—λŠ” 영ν–₯이 μ—†λ‹€.

ν…ŒμŠ€νŠΈ κ²°κ³Ό:

stack1 = [value1, value2, null, null, null, null, null, null, null, null, null, null, null, null, null, null]
stack2 = [value1, value2, value3, null, null, null, null, null, null, null, null, null, null, null, null, null]
  • stack1κ³Ό stack2λŠ” μ„œλ‘œ λ‹€λ₯Έ elements 배열을 가지고 있으며, λ…λ¦½μ μœΌλ‘œ λ™μž‘ν•œλ‹€.

μš”μ•½

  • clone() λ©”μ„œλ“œλ₯Ό μž¬μ •μ˜ν•  λ•ŒλŠ” super.clone()을 ν˜ΈμΆœν•˜μ—¬ 객체의 얕은 볡사λ₯Ό μˆ˜ν–‰ν•œλ‹€.
  • κ°€λ³€ 객체λ₯Ό μ°Έμ‘°ν•˜λŠ” ν•„λ“œλŠ” λ°˜λ“œμ‹œ λ³΅μ œν•˜μ—¬ 원본과 볡제본이 독립적인 객체 μƒνƒœλ₯Ό μœ μ§€ν•˜λ„λ‘ ν•œλ‹€.
  • CloneNotSupportedException은 λ°œμƒν•˜μ§€ μ•Šμ§€λ§Œ μ˜ˆμ™Έ 처리λ₯Ό μœ„ν•΄ try-catch 블둝을 μ‚¬μš©ν•˜κ³ , μ˜ˆμ™Έκ°€ λ°œμƒν•˜λ©΄ AssertionErrorλ₯Ό λ˜μ§„λ‹€.
  • Cloneable μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•΄μ•Ό super.clone()을 ν˜ΈμΆœν•  수 μžˆλ‹€.

{% hint style="info" %} πŸ˜€ μœ„μ˜ λ‚΄μš©μ„ μš”μ•½ν•˜μžλ©΄ {% endhint %}

  • clone() λ©”μ„œλ“œλ₯Ό μž¬μ •μ˜ν•  λ•ŒλŠ” super.clone()을 ν˜ΈμΆœν•˜μ—¬ 객체의 얕은 볡사λ₯Ό μˆ˜ν–‰ν•œλ‹€.
  • κ°€λ³€ 객체λ₯Ό μ°Έμ‘°ν•˜λŠ” ν•„λ“œλŠ” λ°˜λ“œμ‹œ λ³΅μ œν•˜μ—¬ 원본과 볡제본이 독립적인 객체 μƒνƒœλ₯Ό μœ μ§€ν•˜λ„λ‘ νžŒλ‹€.
  • CloneNotSupportedException은 λ°œμƒν•˜μ§€ μ•Šμ§€λ§Œ μ˜ˆμ™Έ 처리λ₯Ό μœ„ν•΄ try-catch 블둝을 μ‚¬μš©ν•˜κ³ , μ˜ˆμ™Έκ°€ λ°œμƒν•˜λ©΄ AssertionErrorλ₯Ό λ˜μ§„λ‹€.
  • Cloneable μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•΄μ•Ό super.clone()을 ν˜ΈμΆœν•  수 μžˆλ‹€.

μ—°κ²° 리슀트의 볡제 방법

μ—°κ²° 리슀트λ₯Ό λ³΅μ œν•  λ•ŒλŠ” 각 λ…Έλ“œλ₯Ό κ°œλ³„μ μœΌλ‘œ 볡사해야 ν•©λ‹ˆλ‹€.

μž¬κ·€μ  볡제의 문제점

μž¬κ·€μ μœΌλ‘œ μ—°κ²° 리슀트λ₯Ό λ³΅μ œν•˜λ©΄ 리슀트의 길이만큼 μŠ€νƒ ν”„λ ˆμž„μ„ μ‚¬μš©ν•˜λ―€λ‘œ, λ¦¬μŠ€νŠΈκ°€ κΈΈλ©΄ μŠ€νƒ μ˜€λ²„ν”Œλ‘œμš°κ°€ λ°œμƒν•  수 μžˆλ‹€.

  • μž¬κ·€μ  볡제 μ½”λ“œ μ˜ˆμ‹œ:
public class Entry {
    Object key;
    Object value;
    Entry next;

    Entry deepCopy() {
        return new Entry(key, value, next == null ? null : next.deepCopy());
    }
}

λ°˜λ³΅λ¬Έμ„ μ‚¬μš©ν•œ 볡제

λ°˜λ³΅λ¬Έμ„ μ‚¬μš©ν•˜λ©΄ μŠ€νƒ μ˜€λ²„ν”Œλ‘œμš°μ˜ μœ„ν—˜ 없이 μ—°κ²° 리슀트λ₯Ό λ³΅μ œν•  수 μžˆλ‹€.

  • λ°˜λ³΅λ¬Έμ„ μ‚¬μš©ν•œ 볡제 μ½”λ“œ μ˜ˆμ‹œ:
public class Entry {
    Object key;
    Object value;
    Entry next;

    Entry deepCopy() {
        Entry result = new Entry(key, value, null);
        Entry p = result;
        Entry q = this.next;
        while (q != null) {
            p.next = new Entry(q.key, q.value, null);
            p = p.next;
            q = q.next;
        }
        return result;
    }
}

μ½”λ“œ μ˜ˆμ‹œ: HashTable 클래슀의 clone() λ©”μ„œλ“œ

public class HashTable implements Cloneable {
    private Entry[] buckets;

    @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(); // λ°œμƒν•˜μ§€ μ•ŠμŒ
        }
    }
}
  • 각 λ²„ν‚·μ˜ μ—°κ²° 리슀트λ₯Ό λ³΅μ œν•˜μ—¬ 원본과 볡제본이 독립적인 μƒνƒœλ₯Ό μœ μ§€ν•©λ‹ˆλ‹€.

4) clone() λ©”μ„œλ“œμ—μ„œ μž¬μ •μ˜ κ°€λŠ₯ν•œ λ©”μ„œλ“œ 호좜 κΈˆμ§€

μž¬μ •μ˜λœ λ©”μ„œλ“œ 호좜의 문제점

clone() λ©”μ„œλ“œμ—μ„œ ν•˜μœ„ ν΄λž˜μŠ€μ—μ„œ μž¬μ •μ˜λœ λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄, ν•˜μœ„ ν΄λž˜μŠ€λŠ” 볡제 κ³Όμ •μ—μ„œ μžμ‹ μ˜ μƒνƒœλ₯Ό 적절히 μ΄ˆκΈ°ν™”ν•  수 μ—†κ²Œ λœλ‹€. μ΄λŠ” 원본과 볡제본의 μƒνƒœκ°€ λ‹¬λΌμ§ˆ 수 μžˆλ‹€λŠ” 것을 의미

ν•΄κ²°μ±…

clone() λ©”μ„œλ“œ λ‚΄μ—μ„œ ν˜ΈμΆœν•˜λŠ” λ©”μ„œλ“œλŠ” final λ˜λŠ” private으둜 μ„ μ–Έν•˜μ—¬ μž¬μ •μ˜λ˜μ§€ μ•Šλ„λ‘ ν•΄μ•Ό ν•œλ‹€.

  • μ˜ˆμ‹œ:
@Override
protected Object clone() throws CloneNotSupportedException {
    MyClass result = (MyClass) super.clone();
    result.init(); // init() λ©”μ„œλ“œλŠ” final λ˜λŠ” private이어야 함
    return result;
}

5) final ν•„λ“œμ™€μ˜ 좩돌 문제

  • λ§Œμ•½ elements ν•„λ“œκ°€ final둜 μ„ μ–Έλ˜μ–΄ μžˆλ‹€λ©΄, clone() λ©”μ„œλ“œμ—μ„œ μƒˆλ‘œμš΄ 배열을 ν• λ‹Ήν•  수 μ—†μ–΄ λ¬Έμ œκ°€ λ°œμƒν•œλ‹€.
  • μ΄λŠ” κ°€λ³€ 객체λ₯Ό μ°Έμ‘°ν•˜λŠ” ν•„λ“œλŠ” final둜 μ„ μ–Έν•˜λΌλŠ” 일반적인 κ·œμΉ™κ³Ό μΆ©λŒν•œλ‹€.
  • μ΄λŸ¬ν•œ 경우, clone() λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜λŠ” λŒ€μ‹  볡사 μƒμ„±μžλ₯Ό μ‚¬μš©ν•˜λŠ” 것이 더 λ°”λžŒμ§ν•˜λ‹€.

볡사 μƒμ„±μž μ‚¬μš© μ˜ˆμ‹œ

public Stack(Stack original) {
    this.elements = original.elements.clone();
    this.size = original.size;
}
  • μž₯점:
    • clone() λ©”μ„œλ“œλ³΄λ‹€ κ΅¬ν˜„μ΄ κ°„λ‹¨ν•˜κ³  λͺ…ν™•ν•˜λ‹€.
    • μ˜ˆμ™Έ μ²˜λ¦¬κ°€ ν•„μš” μ—†λ‹€.
    • final ν•„λ“œμ™€μ˜ 좩돌이 μ—†λ‹€.

μ‚¬μš© μ˜ˆμ‹œ

javaμ½”λ“œ 볡사Stack stack1 = new Stack();
stack1.push("value1");
stack1.push("value2");

Stack stack2 = new Stack(stack1); // 볡사 μƒμ„±μž μ‚¬μš©
stack2.push("value3");
  • stack1κ³Ό stack2λŠ” 독립적인 μŠ€νƒμœΌλ‘œ λ™μž‘ν•œλ‹€.

6) HashTable 클래슀의 μ˜ˆμ‹œμ™€ 문제점

잘λͺ»λœ clone() λ©”μ„œλ“œ:

static class HashTable implements Cloneable {
    private Entry[] buckets;

    private static class Entry {
        final Object key;
        Object value;
        Entry next;

        public Entry(Object 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(); // buckets λ°°μ—΄λ§Œ 볡제
            return result;
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }
}
  • buckets λ°°μ—΄λ§Œ λ³΅μ œν•˜κ³ , λ°°μ—΄ λ‚΄λΆ€μ˜ Entry 객체듀은 λ³΅μ œλ˜μ§€ μ•Šμ•˜λ‹€.
  • 문제점: 볡제된 HashTableκ³Ό 원본 HashTable이 같은 Entry 객체듀을 κ³΅μœ ν•˜κ²Œ λœλ‹€.

7) HashTable 클래슀의 μ˜¬λ°”λ₯Έ clone() λ©”μ„œλ“œ κ΅¬ν˜„

κΉŠμ€ 볡사λ₯Ό μœ„ν•œ clone() λ©”μ„œλ“œ:

static class HashTable implements Cloneable {
    private Entry[] buckets;

    private static class Entry {
        final Object key;
        Object value;
        Entry next;

        public Entry(Object key, Object value, Entry next) {
            this.key = key;
            this.value = value;
            this.next = next;
        }

        // μ—°κ²° 리슀트λ₯Ό κΉŠμ€ λ³΅μ‚¬ν•˜λŠ” λ©”μ„œλ“œ
        Entry deepCopy() {
            Entry result = new Entry(key, value, next);
            Entry p = result;
            while (p.next != null) {
                p.next = new Entry(p.next.key, p.next.value, p.next.next);
                p = p.next;
            }
            return result;
        }
    }

    @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();
        }
    }
}
  • deepCopy() λ©”μ„œλ“œλ₯Ό 톡해 각 λ²„ν‚·μ˜ μ—°κ²° 리슀트λ₯Ό λ³΅μ œν•œλ‹€.
  • κ²°κ³Ό: 볡제된 HashTable은 원본과 독립적인 Entry 객체듀을 κ°€μ§€κ²Œλœλ‹€.

8) deepCopy() λ©”μ„œλ“œμ˜ λ™μž‘ 원리

  • 반볡문 μ‚¬μš©: μž¬κ·€ 호좜 λŒ€μ‹  λ°˜λ³΅λ¬Έμ„ μ‚¬μš©ν•˜μ—¬ μŠ€νƒ μ˜€λ²„ν”Œλ‘œμš°λ₯Ό 방지
  • μƒˆλ‘œμš΄ Entry 객체 생성: μ—°κ²°λœ 각 Entryλ₯Ό μƒˆλ‘œμš΄ 객체둜 μƒμ„±ν•˜μ—¬ λ³΅μ‚¬ν•œλ‹€.
  • 원본과 볡제본의 독립성 보μž₯: 볡제된 객체듀은 원본 객체듀과 λ…λ¦½μ μœΌλ‘œ λ™μž‘ν•œλ‹€.

9) μƒμ„±μžμ—μ„œ μž¬μ •μ˜ κ°€λŠ₯ν•œ λ©”μ„œλ“œ 호좜 κΈˆμ§€

  • μƒμ„±μžμ—μ„œλŠ” μž¬μ •μ˜λ  수 μžˆλŠ” λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ μ•ˆ λ©λ‹ˆλ‹€.
  • λ§Œμ•½ put() λ©”μ„œλ“œλ₯Ό μ΄μš©ν•˜μ—¬ λ³΅μ œν•œλ‹€λ©΄, put() λ©”μ„œλ“œλŠ” final λ˜λŠ” private으둜 μ„ μ–Έλ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€.
  • μ΄λŠ” ν•˜μœ„ ν΄λž˜μŠ€μ—μ„œ λ©”μ„œλ“œλ₯Ό μž¬μ •μ˜ν•˜μ—¬ μ˜ˆμƒμΉ˜ λͺ»ν•œ λ™μž‘μ΄ λ°œμƒν•˜λŠ” 것을 λ°©μ§€ν•©λ‹ˆλ‹€.

4. Cloneable의 문제점 μš”μ•½

  • 언어적인 λͺ¨μˆœκ³Ό μœ„ν—˜μ„±: Cloneableκ³Ό clone() λ©”μ„œλ“œλŠ” 직관적이지 μ•Šκ³  κ΅¬ν˜„ν•˜κΈ° μ–΄λ ΅λ‹€.
  • 얕은 λ³΅μ‚¬μ˜ κΈ°λ³Έ λ™μž‘: 기본적으둜 얕은 볡사가 이루어져 κ°€λ³€ 객체λ₯Ό μ œλŒ€λ‘œ λ³΅μ œν•˜μ§€ λͺ»ν•œλ‹€.
  • final ν•„λ“œμ™€μ˜ 좩돌: final ν•„λ“œλŠ” 볡사 ν›„ 값을 λ³€κ²½ν•  수 μ—†μ–΄ 볡제 μ‹œ λ¬Έμ œκ°€ λ°œμƒν•œλ‹€.
  • μ˜ˆμ™Έ 처리의 λ³΅μž‘μ„±: CloneNotSupportedException λ“± λΆˆν•„μš”ν•œ μ˜ˆμ™Έ μ²˜λ¦¬κ°€ ν•„μš”
  • μž¬μ •μ˜λœ λ©”μ„œλ“œ 호좜 문제: clone() λ©”μ„œλ“œμ—μ„œ μž¬μ •μ˜λœ λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ λ¬Έμ œκ°€ λ°œμƒν•œλ‹€.

5. Clone() λ©”μ„œλ“œ μ£Όμ˜μ‚¬ν•­

  • Object.clone()은 동기화λ₯Ό 신경쓰지 μ•Šμ€ λ©”μ„œλ“œμ΄λ‹€.
    • λ™μ‹œμ„± λ¬Έμ œκ°€ λ°œμƒν•  수 μžˆλ‹€.
  • 만일 clone()을 막고 μ‹Άλ‹€λ©΄ clone() λ©”μ„œλ“œλ₯Ό μž¬μ •μ˜ν•˜μ—¬, CloneNotSupportedException()을 λ˜μ§€λ„λ‘ ν•˜μž.
  • κΈ°λ³Έ νƒ€μž…μ΄λ‚˜ λΆˆλ³€ 객체 참쑰만 가지면 아무것도 μˆ˜μ •ν•  ν•„μš” μ—†μœΌλ‚˜ 일련번호 ν˜Ήμ€ 고유 ID와 같은 값을 가지고 μžˆλ‹€λ©΄, 비둝 λΆˆλ³€μΌμ§€λΌλ„ μƒˆλ‘­κ²Œ μˆ˜μ •ν•΄μ€˜μ•Ό 함

6. 볡사 μƒμ„±μž 및 볡사 νŒ©ν„°λ¦¬ λ©”μ„œλ“œ

{% hint style="info" %} 볡사 μƒμ„±μžλž€ λ‹¨μˆœνžˆ μžμ‹ κ³Ό 같은 클래슀의 μΈμŠ€ν„΄μŠ€λ₯Ό 인수둜 λ°›λŠ” μƒμ„±μžλ₯Ό λ§ν•œλ‹€. {% endhint %}

Cloneable μΈν„°νŽ˜μ΄μŠ€μ™€ clone() λ©”μ„œλ“œ λŒ€μ‹  볡사 μƒμ„±μžμ™€ 볡사 νŒ©ν„°λ¦¬ λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜λŠ” 것이 μ’‹λ‹€.

  • 볡사 νŒ©ν„°λ¦¬ λ©”μ„œλ“œ: 볡사 μƒμ„±μžμ™€ μœ μ‚¬ν•˜μ§€λ§Œ 정적 νŒ©ν„°λ¦¬ λ©”μ„œλ“œλ‘œ κ΅¬ν˜„λœλ‹€.
  • Cloneable을 이미 κ΅¬ν˜„ν•œ 클래슀λ₯Ό ν™•μž₯ν•œλ‹€λ©΄ μ–΄μ©” 수 없이 clone을 잘 μž‘λ™ν•˜λ„λ‘ κ΅¬ν˜„ν•΄μ•Ό ν•œλ‹€. 그렇지 μ•Šμ€ μƒν™©μ—μ„œλŠ” 볡사 μƒμ„±μžμ™€ 볡사 νŒ©ν„°λ¦¬λΌλŠ” 더 λ‚˜μ€ 객체 볡사 방식을 μ œκ³΅ν•  수 μžˆλ‹€.

볡사 μƒμ„±μž

public class Yum {
    private int value;

    // 볡사 μƒμ„±μž
    public Yum(Yum yum) {
        this.value = yum.value;
    }
}

볡사 νŒ©ν„°λ¦¬ λ©”μ„œλ“œ

public class Yum {
    private int value;

    private Yum(int value) {
        this.value = value;
    }

    // 볡사 νŒ©ν„°λ¦¬ λ©”μ„œλ“œ
    public static Yum newInstance(Yum yum) {
        return new Yum(yum.value);
    }
}

볡사 μƒμ„±μžμ™€ 볡사 νŒ©ν„°λ¦¬μ˜ μž₯점

  • 직관적인 객체 생성: μƒμ„±μžλ‚˜ 정적 λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜λ―€λ‘œ 객체 생성 방식이 λͺ…ν™•
  • μ•ˆμ „μ„±: Cloneable의 λ³΅μž‘ν•œ κ·œμ•½μ— μ˜μ‘΄ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ κ΅¬ν˜„ μ‹€μˆ˜μ˜ μœ„ν—˜μ΄ 적닀.
  • μœ μ—°μ„±: ν•„μš”ν•œ 경우 볡사 κ³Όμ •μ—μ„œ ν•„λ“œλ₯Ό λ³€ν™˜ν•˜κ±°λ‚˜ μˆ˜μ •ν•  수 μžˆλ‹€.
  • μ˜ˆμ™Έ 처리 κ°„μ†Œν™”: λΆˆν•„μš”ν•œ μ˜ˆμ™Έλ₯Ό λ˜μ§€μ§€ μ•ŠμœΌλ―€λ‘œ μ‚¬μš©ν•˜κΈ° νŽΈλ¦¬ν•©
  • ν˜•λ³€ν™˜ λΆˆν•„μš”: λ°˜ν™˜ νƒ€μž…μ΄ λͺ…ν™•ν•˜λ―€λ‘œ ν˜•λ³€ν™˜ν•  ν•„μš”κ°€ μ—†λ‹€.

볡사 μƒμ„±μžλž‘ 볡사 νŒ©ν„°λ¦¬λ‘œ clone() κ΅¬ν˜„ν•˜κΈ°

/**
 * Constructs a new {@code HashMap} with the same mappings as the
 * specified {@code Map}.  The {@code HashMap} is created with
 * default load factor (0.75) and an initial capacity sufficient to
 * hold the mappings in the specified {@code Map}.
 *
 * @param   m the map whose mappings are to be placed in this map
 * @throws  NullPointerException if the specified map is null
 */
public HashMap(Map<? extends K, ? extends V> m) {
    this.loadFactor = DEFAULT_LOAD_FACTOR;
    putMapEntries(m, false);
}
  • μœ„λŠ” HashMapμ—μ„œ μ œκ³΅ν•˜λŠ” 볡사 μƒμ„±μžλ‘œ λ³Ό 수 μžˆλ‹€.

더 μ •ν™•ν•œ 이름은 λ³€ν™˜ μƒμ„±μž(conversion constructor)와 λ³€ν™˜ νŒ©ν„°λ¦¬(conversion factory)이닀.

ArrayList

λ³€ν™˜ μƒμ„±μž μ˜ˆμ‹œ: ArrayList

이 방식은 clone() λ©”μ„œλ“œλ³΄λ‹€ μ—¬λŸ¬ λ©΄μ—μ„œ 더 λ‚«μŠ΅λ‹ˆλ‹€. ArrayListλŠ” clone() λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜κΈ°λ³΄λ‹€, λ‹€λ₯Έ μ»¬λ ‰μ…˜μ˜ μš”μ†Œλ₯Ό λ°›μ•„λ“€μ΄λŠ” μƒμ„±μžλ₯Ό μ œκ³΅ν•œλ‹€.

주석이 ν¬ν•¨λœ μ½”λ“œ 예제:

/**
 * μ§€μ •λœ μ»¬λ ‰μ…˜μ˜ μš”μ†Œλ₯Ό μˆœμ„œλŒ€λ‘œ ν¬ν•¨ν•˜λŠ” 리슀트λ₯Ό μƒμ„±ν•©λ‹ˆλ‹€.
 *
 * @param c 이 λ¦¬μŠ€νŠΈμ— 좔가될 μš”μ†Œλ₯Ό ν¬ν•¨ν•˜λŠ” μ»¬λ ‰μ…˜
 * @throws NullPointerException μ§€μ •λœ μ»¬λ ‰μ…˜μ΄ null인 경우
 */
public ArrayList(Collection<? extends E> c) {
    // μ»¬λ ‰μ…˜μ˜ μš”μ†Œλ₯Ό λ°°μ—΄λ‘œ λ³€ν™˜ν•©λ‹ˆλ‹€.
    elementData = c.toArray();
    // 리슀트의 크기λ₯Ό μ„€μ •ν•©λ‹ˆλ‹€.
    size = elementData.length;
    // c.toArray()κ°€ Object[]λ₯Ό λ°˜ν™˜ν•˜μ§€ μ•Šμ„ 수 μžˆμœΌλ―€λ‘œ, λ°°μ—΄μ˜ νƒ€μž…μ„ Object[]둜 보μž₯ν•©λ‹ˆλ‹€.
    if (elementData.getClass() != Object[].class)
        elementData = Arrays.copyOf(elementData, size, Object[].class);
}

μ„€λͺ…:

  • λͺ©μ : 이 μƒμ„±μžλŠ” μ§€μ •λœ μ»¬λ ‰μ…˜ c의 λͺ¨λ“  μš”μ†Œλ₯Ό ν¬ν•¨ν•˜λŠ” μƒˆλ‘œμš΄ ArrayList μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•œλ‹€λ‹€. μš”μ†Œλ“€μ€ μ»¬λ ‰μ…˜μ˜ μ΄ν„°λ ˆμ΄ν„°κ°€ λ°˜ν™˜ν•˜λŠ” μˆœμ„œλ₯Ό λ”°λ₯Έλ‹€.
  • μžμ„Έν•œ μž₯점:
    1. 클둠 λ©”μ»€λ‹ˆμ¦˜μ˜ 문제 νšŒν”Ό:
      • clone() λ©”μ„œλ“œλŠ” 얕은 λ³΅μ‚¬λ‘œ 인해 κ°€λ³€ 객체λ₯Ό μ˜¬λ°”λ₯΄κ²Œ λ³΅μ œν•˜μ§€ λͺ»ν•˜λŠ” λ“±μ˜ λ¬Έμ œκ°€ μžˆλ‹€.
      • μƒμ„±μžλ₯Ό μ‚¬μš©ν•˜λ©΄ 볡제 κ³Όμ •μ—μ„œ μ™„μ „ν•œ ν†΅μ œλ₯Ό ν•  수 μžˆλ‹€.
    2. μΈν„°νŽ˜μ΄μŠ€ νƒ€μž… 수용:
      • Collection<? extends E>λ₯Ό 인수둜 λ°›μœΌλ―€λ‘œ, List, Set λ“± λ‹€μ–‘ν•œ μ»¬λ ‰μ…˜μ„ 인수둜 받을 수 μžˆλ‹€.
      • 이λ₯Ό 톡해 μƒμ„±μžμ˜ ν™œμš© λ²”μœ„κ°€ 넓어짐
    3. ν˜•λ³€ν™˜ λΆˆν•„μš”:
      • λ‚΄λΆ€μ μœΌλ‘œ νƒ€μž… λ³€ν™˜μ„ μ²˜λ¦¬ν•˜λ―€λ‘œ, 호좜 μ‹œμ— λ³„λ„μ˜ ν˜•λ³€ν™˜μ΄ ν•„μš” μ—†λ‹€.
      • λŸ°νƒ€μž„ μ‹œ ClassCastException이 λ°œμƒν•  μœ„ν—˜μ„ 쀄인닀.
    4. 검사 μ˜ˆμ™Έ 처리 κ°„μ†Œν™”:
      • clone() λ©”μ„œλ“œλŠ” CloneNotSupportedException을 μ²˜λ¦¬ν•΄μ•Ό ν•˜μ§€λ§Œ, 이 μƒμ„±μžλŠ” 그런 μ˜ˆμ™Έλ₯Ό λ˜μ§€μ§€ μ•Šμ•„ μ‚¬μš©μ΄ κ°„νŽΈ
    5. final ν•„λ“œμ˜ μ˜¬λ°”λ₯Έ μ΄ˆκΈ°ν™”:
      • μƒμ„±μžλ₯Ό μ‚¬μš©ν•˜λ©΄ final ν•„λ“œλ₯Ό 적절히 μ΄ˆκΈ°ν™”ν•  수 μžˆμ§€λ§Œ, clone()은 μƒμ„±μžλ₯Ό ν˜ΈμΆœν•˜μ§€ μ•ŠμœΌλ―€λ‘œ final ν•„λ“œ μ΄ˆκΈ°ν™”μ— λ¬Έμ œκ°€ 생길 수 μžˆλ‹€.

μ‚¬μš© μ˜ˆμ‹œ

// 원본 μ»¬λ ‰μ…˜
Collection<String> originalCollection = Arrays.asList("사과", "λ°”λ‚˜λ‚˜", "체리");

// λ³€ν™˜ μƒμ„±μžλ₯Ό μ‚¬μš©ν•˜μ—¬ μƒˆλ‘œμš΄ ArrayList 생성
ArrayList<String> fruitList = new ArrayList<>(originalCollection);

// μƒˆλ‘œμš΄ λ¦¬μŠ€νŠΈμ— μš”μ†Œ μΆ”κ°€
fruitList.add("데이트");

// 원본 μ»¬λ ‰μ…˜μ€ λ³€κ²½λ˜μ§€ μ•ŠμŒ
System.out.println("원본 μ»¬λ ‰μ…˜: " + originalCollection); // [사과, λ°”λ‚˜λ‚˜, 체리]
System.out.println("과일 리슀트: " + fruitList); // [사과, λ°”λ‚˜λ‚˜, 체리, 데이트]

✨ 결둠

객체 볡사λ₯Ό ν•„μš”λ‘œ ν•  λ•ŒλŠ” Cloneableκ³Ό clone() λ©”μ„œλ“œλ³΄λ‹€λŠ” 볡사 μƒμ„±μžλ‚˜ 볡사 νŒ©ν„°λ¦¬ λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜λŠ” 것이 더 μ•ˆμ „ν•˜κ³  ꢌμž₯λ˜λŠ” 방법

Cloneable이 λͺ°κ³  온 λͺ¨λ“  문제λ₯Ό λ˜μ§šμ–΄λ΄€μ„ λ•Œ, μƒˆλ‘œμš΄ μΈν„°νŽ˜μ΄μŠ€λ₯Ό λ§Œλ“€ λ•ŒλŠ” μ ˆλŒ€ Cloneable을 ν™•μž₯ν•΄μ„œλŠ” μ•ˆ 되며, μƒˆλ‘œμš΄ ν΄λž˜μŠ€λ„ 이λ₯Ό κ΅¬ν˜„ν•΄μ„œλŠ” μ•ˆ λœλ‹€.

  • μƒˆλ‘œμš΄ ν΄λž˜μŠ€λ‚˜ μΈν„°νŽ˜μ΄μŠ€λ₯Ό λ§Œλ“€ λ•Œ Cloneable을 κ΅¬ν˜„ν•˜κ±°λ‚˜ ν™•μž₯ν•˜μ§€ 말아라
    • Cloneable은 λ§Žμ€ λ¬Έμ œμ μ„ 가지고 μžˆμ–΄ μ‚¬μš©μ„ ꢌμž₯ν•˜μ§€ μ•ŠλŠ”λ‹€.
  • 볡제 κΈ°λŠ₯은 볡사 μƒμ„±μžλ‚˜ 볡사 νŒ©ν„°λ¦¬ λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•΄λΌ
    • 더 μ•ˆμ „ν•˜κ³  μœ μ—°ν•˜λ©°, μ΄ν•΄ν•˜κΈ° 쉽닀.
    • 이듀은 μ½”λ“œκ°€ λͺ…ν™•ν•˜κ³  μ΄ν•΄ν•˜κΈ° μ‰¬μš°λ©°, final ν•„λ“œμ™€λ„ μΆ©λŒν•˜μ§€ μ•Šκ³ , λΆˆν•„μš”ν•œ μ˜ˆμ™Έ μ²˜λ¦¬λ‚˜ ν˜•λ³€ν™˜μ΄ ν•„μš”ν•˜μ§€ μ•ŠλŠ”λ‹€.
  • 배열은 μ˜ˆμ™Έ
    • 배열은 clone() λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ λ³΅μ œν•˜λŠ” 것이 κ°€μž₯ κΉ”λ”ν•˜κ³  효율적

++ native λ©”μ„œλ“œ

native: λ©”μ„œλ“œλŠ” Cλ‚˜ C++ 같은 λ„€μ΄ν‹°λΈŒ ν”„λ‘œκ·Έλž˜λ° μ–Έμ–΄λ‘œ μž‘μ„±ν•œ λ©”μ„œλ“œλ₯Ό μ˜λ―Έν•œλ‹€. Java Native Interface(JNI)라고 λΆ€λ₯Έλ‹€. 즉, Cλ‚˜ C++의 μ½”λ“œλ₯Ό μžλ°”μ—μ„œ 뢈러 μ‚¬μš©ν•˜λ €λ©΄ native λ©”μ„œλ“œλ₯Ό μ •μ˜ν•΄μ„œ λ©”μ„œλ“œ λ°”λ””λ₯Ό 갖지 μ•ŠλŠ” λ©”μ„œλ“œλ₯Ό κ΅¬ν˜„ν•œλ‹€. (λ©”μ„œλ“œ λ°”λ””κ°€ dll (Unix에선 so) 파일둜 λ˜μ–΄ μžˆμ–΄ λŸ°νƒ€μž„ μ‹œμ— dll νŒŒμΌμ„ System.loadLibrary λ©”μ„œλ“œκ°€ μˆ˜ν–‰ν•˜μ—¬ classpath κ²½λ‘œμ—μ„œ νŒŒλΌλ―Έν„°μ˜ νŒŒμΌμ„ λ©”λͺ¨λ¦¬μ— λ‘œλ”©)

μ°Έκ³  및 일뢀 κ°€μ Έμ˜€κΈ° : https://jake-seo-dev.tistory.com/31#%EB%B-%B-%EC%--%AC%--%EC%--%-D%EC%--%B-%EC%-E%--%EC%--%--%--%EB%B-%B-%EC%--%AC%--%ED%-C%A-%ED%--%B-%EB%A-%AC%EB%A-%-C%--clone--%--%EA%B-%AC%ED%--%--%ED%--%--%EA%B-%B-

Footnotes

  1. AssertionErrorλž€ λ¬΄μ—‡μΈκ°€μš”?

    AssertionErrorλŠ” μžλ°”μ—μ„œ μ—λŸ¬(Error)의 ν•œ μ’…λ₯˜λ‘œ, 주둜 ν”„λ‘œκ·Έλž¨μ˜ 논리적인 였λ₯˜κ°€ λ°œμƒν–ˆμ„ λ•Œ μ‚¬μš©λ©λ‹ˆλ‹€. 이 μ—λŸ¬λŠ” 일반적으둜 κ°œλ°œμžκ°€ μ˜ˆμΈ‘ν•  수 μ—†λŠ” 상황이 λ°œμƒν–ˆμ„ λ•Œ 이λ₯Ό μ•Œλ¦¬κΈ° μœ„ν•΄ λ˜μ§‘λ‹ˆλ‹€.

    1. AssertionError의 λͺ©μ 

    • 개발 μ€‘μ—λ§Œ μ‚¬μš©: AssertionErrorλŠ” 주둜 개발 및 디버깅 λ‹¨κ³„μ—μ„œ ν”„λ‘œκ·Έλž¨μ˜ λ‚΄λΆ€ μƒνƒœλ₯Ό κ²€μ¦ν•˜κΈ° μœ„ν•΄ μ‚¬μš©λ©λ‹ˆλ‹€.
    • λΆˆκ°€λŠ₯ν•œ 상황을 λ‚˜νƒ€λƒ„: μ½”λ“œμ—μ„œ μ ˆλŒ€λ‘œ λ°œμƒν•΄μ„œλŠ” μ•ˆ λ˜λŠ” 상황이 λ°œμƒν–ˆμ„ λ•Œ 이λ₯Ό μ•Œλ¦¬κΈ° μœ„ν•΄ μ‚¬μš©ν•©λ‹ˆλ‹€.
    • μ˜ˆμ™Έ 처리의 κ°„μ†Œν™”: 검사 μ˜ˆμ™Έ(checked exception)λ₯Ό μ²˜λ¦¬ν•΄μ•Ό ν•˜λŠ” λ²ˆκ±°λ‘œμ›€μ„ ν”Όν•˜κΈ° μœ„ν•΄ μ‚¬μš©λ©λ‹ˆλ‹€.
    ↩