깊은 복사

객체를 복사할 때 내부에 참조하는 객체들까지 모두 새로 생성해서 완전히 독립적인 복사본을 만드는 방식입니다.

원본과 복사본이 서로 전혀 영향을 주지 않습니다.


Java 예시

import java.util.Arrays;

class Person {
    String name;
    int[] scores;

    Person(String name, int[] scores) {
        this.name = name;
        this.scores = scores;
    }

    // 깊은 복사
    Person deepCopy() {
        int[] newScores = Arrays.copyOf(this.scores, this.scores.length);  // 배열도 새로 생성
        return new Person(this.name, newScores);
    }
}

public class Main {
    public static void main(String[] args) {
        int[] originalScores = {90, 85, 88};
        Person original = new Person("김철수", originalScores);

        // 깊은 복사 수행
        Person copied = original.deepCopy();

        // 복사본의 scores 수정
        copied.scores[0] = 100;

        // 원본은 그대로!
        System.out.println("원본 scores: " + Arrays.toString(original.scores));
        // 출력: [90, 85, 88]

        System.out.println("복사본 scores: " + Arrays.toString(copied.scores));
        // 출력: [100, 85, 88]
    }
}

메모리 구조

[원본 Person]              [복사본 Person]
┌─────────────┐           ┌─────────────┐
│ name: "김철수"│           │ name: "김철수"│
│ scores: ────┼──┐     ┌──┼─ scores     │
└─────────────┘  │     │  └─────────────┘
                 ▼     ▼
         ┌──────────┐  ┌──────────┐
         │[90,85,88]│  │[100,85,88]│  ← 각자 별도의 배열!
         └──────────┘  └──────────┘

깊은 복사 구현 방법들

1. 직접 구현

Person deepCopy() {
    int[] newScores = new int[this.scores.length];
    for (int i = 0; i < scores.length; i++) {
        newScores[i] = this.scores[i];
    }
    return new Person(this.name, newScores);
}

2. Cloneable 인터페이스

class Person implements Cloneable {
    String name;
    int[] scores;

    @Override
    protected Person clone() throws CloneNotSupportedException {
        Person cloned = (Person) super.clone();
        cloned.scores = this.scores.clone();  // 참조 타입도 복제
        return cloned;
    }
}

3. 직렬화 활용 (객체가 복잡할 때)

// Serializable 구현 후
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(original);

ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
Person copied = (Person) ois.readObject();

핵심 정리

상황선택
내부 객체 수정이 없을 때얕은 복사 (빠름)
완전 독립이 필요할 때깊은 복사 (안전)

깊은 복사의 핵심은 참조 타입 필드를 재귀적으로 모두 새로 생성하는 것입니다.

CSLOG에서 보기