728x90
반응형
얕은 복사(Shallow Copy)와 깊은 복사(Deep Copy)의 개념
- 얕은 복사: 객체의 주소만 복사하여 동일한 객체를 공유
- 깊은 복사: 참조 객체도 새롭게 생성하여 원본과 독립적인 객체로 복제
얕은 복사(Shallow Copy)
- 객체를 복사할 때, 주소값만 복사하는 방식
- 원본 객체와 복사된 객체가 같은 참조값을 공유하게 되어 한쪽에서 값을 변경하면 다른 쪽에도 영향을 미침
🔹 얕은 복사 예제
class Person {
String name;
Person(String name) {
this.name = name;
}
}
class ShallowCopyTest {
public static void main(String[] args) {
Person person1 = new Person("Alice");
Person person2 = person1; // 얕은 복사 (같은 객체를 가리킴)
person2.name = "Bob"; // person2의 값을 변경하면 person1도 영향을 받음
System.out.println(person1.name); // Bob
System.out.println(person2.name); // Bob
}
}
➡ person1과 person2가 동일한 객체를 가리키므로, 하나를 변경하면 다른 객체도 영향을 받음
깊은 복사(Deep Copy)
- 새로운 객체를 생성한 후, 원본 객체의 모든 필드 값을 복사하지만 참조형 변수(객체 타입 변수)도 새로운 객체로 생성하는 방식
- 원본 객체와 복사된 객체는 완전히 독립적인 객체가 됨
- 따라서 한쪽을 변경해도 다른 쪽에는 영향을 미치지 않음
아래 예시들은 참조 데이터(객체)를 깊은 복사하는 예제를 해 볼거다.
※List, Map의 깊은 복사는 아래 링크로 이동
Java 리스트(List), Map 의 깊은 복사 완벽 정리 (+ 예제 코드)
Java에서 Map, List, String의 깊은 복사 방법Java에서 Map, List, String을 깊은 복사하는 방법을 살펴보겠습니다.1. ArrayList 깊은 복사방법 1: for 루프 사용 (가장 기본적인 방법)List deepCopy = new ArrayList();for (I
bears-paw.tistory.com
1. 수동 복사 (Manual Deep Copy)
- 복사 생성자를 사용하여 객체 내부의 참조 타입 필드도 새롭게 생성하여 복사
class Address {
String city;
Address(String city) {
this.city = city;
}
}
class Person {
String name;
Address address; // 참조 타입 필드
Person(String name, Address address) {
this.name = name;
this.address = address;
}
// 깊은 복사 생성자
Person(Person original) {
this.name = original.name;
this.address = new Address(original.address.city); // 새로운 객체 생성
}
}
class DeepCopyTest {
public static void main(String[] args) {
Person person1 = new Person("Alice", new Address("Seoul"));
Person person2 = new Person(person1); // 깊은 복사
person2.name = "Bob";
person2.address.city = "Busan"; // 원본 객체의 값은 변경되지 않음
System.out.println(person1.name + " - " + person1.address.city); // Alice - Seoul
System.out.println(person2.name + " - " + person2.address.city); // Bob - Busan
}
}
➡ 참조 타입 필드(Address)도 새로운 객체를 만들어서 복사했기 때문에 독립적인 객체가 됨
2. clone() 메서드 오버라이딩
- Cloneable 인터페이스를 구현하고 clone() 메서드를 오버라이딩하여 깊은 복사를 수행
- Object의 clone() 메서드는 얕은 복사를 수행하기 때문에, 내부의 참조 타입 필드를 직접 복사해야 함
class Address implements Cloneable {
String city;
Address(String city) {
this.city = city;
}
// 깊은 복사
@Override
protected Object clone() throws CloneNotSupportedException {
return new Address(this.city);
}
}
class Person implements Cloneable {
String name;
Address address;
Person(String name, Address address) {
this.name = name;
this.address = address;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Person cloned = (Person) super.clone(); // 얕은 복사
cloned.address = (Address) this.address.clone(); // 깊은 복사
return cloned;
}
}
class DeepCopyTest {
public static void main(String[] args) throws CloneNotSupportedException {
Person person1 = new Person("Alice", new Address("Seoul"));
Person person2 = (Person) person1.clone(); // 깊은 복사 수행
person2.name = "Bob";
person2.address.city = "Busan"; // 원본 객체에는 영향 없음
System.out.println(person1.name + " - " + person1.address.city); // Alice - Seoul
System.out.println(person2.name + " - " + person2.address.city); // Bob - Busan
}
}
➡ clone()을 이용하여 참조 타입 객체도 새롭게 복사하여 깊은 복사를 수행
3. JSON 변환을 이용한 깊은 복사
- Jackson, Gson 등의 라이브러리를 사용하여 객체를 JSON으로 변환 후 다시 객체로 변환하면 깊은 복사가 가능
- 예제: Gson 라이브러리 사용
import com.google.gson.Gson;
class DeepCopyTest {
public static void main(String[] args) {
Gson gson = new Gson();
Person person1 = new Person("Alice", new Address("Seoul"));
String json = gson.toJson(person1); // 객체를 JSON 문자열로 변환
Person person2 = gson.fromJson(json, Person.class); // JSON 문자열을 객체로 변환 (깊은 복사)
person2.name = "Bob";
person2.address.city = "Busan"; // 원본 객체에는 영향 없음
System.out.println(person1.name + " - " + person1.address.city); // Alice - Seoul
System.out.println(person2.name + " - " + person2.address.city); // Bob - Busan
}
}
➡ Gson을 이용하면 쉽게 깊은 복사가 가능
결론
- 얕은 복사: 객체의 주소만 복사하여 동일한 객체를 공유
- 깊은 복사: 참조 객체도 새롭게 생성하여 원본과 독립적인 객체로 복제
- 깊은 복사 방법
- 수동 복사 (생성자 이용)
- clone() 메서드 오버라이딩
- 직렬화(Serialization)
- JSON 변환(Gson, Jackson 등 활용)
가장 쉬운 방법: Gson, Jackson
안전한 방법: clone(), Serializable
속도가 빠른 방법: 생성자 수동 복사
★용도에 맞게 잘 사용해보자!
728x90
반응형
'프로그래밍 > JAVA' 카테고리의 다른 글
Java 제네릭(Generic) 쉽게 이해하기 – 타입 안정성과 코드 재사용성 극대화 (3) | 2025.03.04 |
---|---|
Java 리스트(List), Map 의 깊은 복사 완벽 정리 (+ 예제 코드) (0) | 2025.03.03 |
Java 불변 객체(Immutable Object)란? 불변객체 vs 가변객체 정리 (0) | 2025.03.03 |
객체 지향 프로그래밍(OOP)란? 객체 지향 프로그래밍(OOP) vs 함수형 프로그래밍(FP) 차이점 (1) | 2025.03.03 |
Java 자주 사용되는 디자인 패턴 정리! (0) | 2025.03.03 |
댓글