Java에서 객체를 복사하는 방법에는 2가지 방식이 있다. 하나는 “얕은 복사”, 다른 하나는 “깊은 복사” 이다.
이에 알아보기 앞서, Book과 Author라는 클래스를 사용한 예제를 통해 알아보자.
class Book {
private String name; // 책 이름
private Author author; // 저자
public Book(String name, Author author) {
this.name = name;
this.author = author;
}
// 얕은 복사
public Book shallowCopy() {
return new Book(this.name, this.author);
}
// 깊은 복사
public Book deepCopy() {
Author copiedAuthor = new Author(this.author.getName());
return new Book(this.name, copiedAuthor);
}
// 저자 이름 변경
public void changeAuthor(String name) {
author.setName(name);
}
@Override
public String toString() {
return "Book name : " + name + ", " + author;
}
static class Author {
private String name; // 저자 이름
public Author(String name) {
this.name = name;
}
public String getName() { // 저자 이름 반환
return name;
}
public void setName(String name) { // 저자 이름 변경
this.name = name;
}
@Override
public String toString() {
return "Author : " + name;
}
}
public static void main(String[] args) {
Author author1 = new Author("캐시 시에라");
Book book1 = new Book("헤드퍼스트 자바", author1);
// 얕은 복사 후 변경
Book shallowCopyBook = book1.shallowCopy();
shallowCopyBook.changeAuthor("Kathy Sierra");
// 얕은 복사 결과 출력
System.out.println("After shallow copy and change:");
System.out.println("Original book1: " + book1);
System.out.println("Shallow copied book: " + shallowCopyBook);
/*
(출력 결과)
After shallow copy and change:
Original book1: Book name : 헤드퍼스트 자바, Author : Kathy Sierra
Shallow copied book: Book name : 헤드퍼스트 자바, Author : Kathy Sierra
*/
Author author2 = new Author("조슈아 블로크");
Book book2 = new Book("이펙티브 자바", author2);
// 깊은 복사 후 변경
Book deepCopyBook = book2.deepCopy();
deepCopyBook.changeAuthor("Joshua Bloch");
// 깊은 복사 결과 출력
System.out.println("After deep copy and change:");
System.out.println("Original book2: " + book2);
System.out.println("Deep copied book: " + deepCopyBook);
/*
(출력 결과)
After deep copy and change:
Original book2: Book name : 이펙티브 자바, Author : 조슈아 블로크
Deep copied book: Book name : 이펙티브 자바, Author : Joshua Bloch
*/
}
}
얕은 복사는 객체의 필드 값만 그대로 복사 하는 방식이다. 즉, 기본 타입은 값 복사, 참조 타입은 주소(참조)만 복사해서 원본 객체와 복사된 객체가 같은 객체를 참조 하게 된다.
위의 코드를 보면, shallowCopy 메서드는 새로운 Book 객체를 만들지만, 내부의 Author 객체는 원본과 동일한 객체를 참조한다. 쉽게 말해, Book 객체는 새로 만든 것이고, Author 객체는 새로 만든 것이 아닌 기존의 것을 그대로 사용한다는 말이다.
book1에서 shallowCopyBook을 만들고, shallowCopyBook의 저자 이름을 “Kathy Sierra” 로 변경하면 book1의 저자 이름도 “Kathy Sierra” 로 바뀌는 것이다. 왜냐하면 book1과 shallowCopyBook은 같은 Author 객체를 공유하고 있기 때문이다.
따라서, shallowCopyBook과 book1이 같은 Author 객체를 공유하기 때문에, shallowCopyBook의 저자 이름을 바꾸면 book1의 저자 이름도 바뀌는 것을 확인할 수 있다.
| 항목 | 내용 |
|---|---|
| 🔁 복사 속도 | 빠르다 (참조 주소만 복사) |
| 📦 메모리 사용량 | 적게 든다 |
| 💣 데이터 공유 | 참조형 필드를 공유하므로, 한쪽에서 내부 객체를 변경하면 다른 쪽에도 반영됨 |
| 🔍 사용 용도 | 구조가 단순하고 하위 객체가 불변일 때 적합 |
| 🔧 구현 방법 | Object.clone() 또는 단순한 대입(=) |
깊은 복사는 객체 전체를 복사 하면서, 그 안에 포함된 참조 객체들도 새롭게 복사해서 원본과 완전히 독립된 객체 를 만드는 방식이다.
앞서 살펴보았던 얕은 복사와는 달리, deepCopy 메서드는 Book 객체와 Author 객체 모두 새로운 객체로 만들어주는 것이다. book2에서 deepCopyBook을 만들고 저자 이름을 “Joshua Bloch” 로 바꿔도, book2의 저자 이름은 그대로 “조슈아 블로크” 로 남아 있다. 왜냐하면 book2와 deepCopyBook은 서로 다른 Author 객체를 참조하고 있기 때문이다.
출력 결과를 확인해보면, deepCopyBook과 book2는 서로 다른 Author 객체를 참조하기 때문에, deepCopyBook의 저자 이름을 바꾼다 하더라도 book2는 아무 영향을 받지 않는 것을 볼 수 있다.
| 항목 | 내용 |
|---|---|
| 🔁 복사 속도 | 상대적으로 느림 (객체 구조 전체 복사 필요) |
| 📦 메모리 사용량 | 많다 (모든 객체를 새로 생성하므로) |
| 💣 데이터 공유 | 공유하지 않음 → 한쪽 변경해도 다른 쪽에 영향 없음 |
| 🔍 사용 용도 | 하위 객체도 변경 가능성이 있을 때 안전하게 사용 |
| 🔧 구현 방법 | 수동 복사, clone 메서드 재정의, 직렬화(serialization) 등 |