프로그래밍Java 개발자

Java에서 얕은 복사(shallow copy)와 깊은 복사(deep copy) 간의 차이를 설명하십시오. 그들은 어떻게 구현되며, 언제 필요할 수 있습니까?

Hintsage AI 어시스턴트로 면접 통과

답변

**얕은 복사(shallow copy)**는 새 객체를 생성하지만 중첩 객체에 대한 참조를 복사할 뿐 실제 객체는 복사하지 않습니다. **깊은 복사(deep copy)**는 새 객체를 생성하고 원래 객체에 포함된 모든 객체를 재귀적으로 복사하여 복사본과 원본 사이에 공유 참조가 없도록 합니다.

언제 사용해야 할까요:

  • 객체의 구조가 변경할 수 없는 중첩 객체를 포함하지 않거나 중첩 객체를 변경할 필요가 없는 경우 얕은 복사로 충분합니다.
  • 중첩 객체의 변경 가능성이 중요하고 복사본에서의 모든 수정이 원본에 반영되지 않아야 하는 경우 깊은 복사가 필요합니다.

구현 예제:

// 중첩 객체가 있는 클래스의 예 class Address { String city; Address(String city) { this.city = city; } } class Person implements Cloneable { String name; Address address; Person(String name, Address address) { this.name = name; this.address = address; } // 얕은 복사 public Person clone() throws CloneNotSupportedException { return (Person) super.clone(); } // 깊은 복사 public Person deepClone() { return new Person(this.name, new Address(this.address.city)); } }

함정 질문

clone() 메소드를 사용하여 깊은 복사를 구현할 수 있을까요?

답변: 아니요, 표준 메소드 Object.clone()는 단지 "얕은 복사"만 구현합니다. 깊은 복사를 얻으려면 모든 중첩 필드를 수동으로 복제하거나 서드 파티 라이브러리(예: Apache Commons Lang)를 사용해야 합니다.

예제:

@Override public Person clone() throws CloneNotSupportedException { Person cloned = (Person) super.clone(); cloned.address = new Address(this.address.city); // 수동으로 깊은 복사 return cloned; }

이야기

대규모 CRM 프로젝트에서 super.clone()을 통해 객체 복사를 구현한 후, 개발자는 복사본의 완전한 독립성을 기대했습니다. 그러나 복사된 사용자의 주소를 변경하자 원본 주소도 변경되었습니다. 이 버그는 릴리스 후에 발견되어 고객 데이터베이스에서 혼란을 야기했습니다.


이야기

깊은 복사를 위한 직렬화/역직렬화를 위해 표준 메커니즘인 Serializable을 선택했습니다. 그러나 중첩 객체의 하나의 필드를 Serializable로 선언하는 것을 잊어버려서 실행 중 오류(NotSerializableException)가 발생하고 백업 시 데이터 손실이 발생했습니다.


이야기

한 마이크로서비스에서 DTO 복사를 위해 BeanUtils.copyProperties 복사 라이브러리를 사용했지만 메커니즘이 오직 얕은 복사를 구현하고 있다는 사실을 인식하지 못했습니다. 이후 리팩토링 과정에서 중첩 컬렉션의 변경이 데이터베이스에서 가져온 원본 데이터에 영향을 미치는 여러 가지 명백하지 않은 버그가 발생했습니다.