프로그래밍자바 개발자

자바에서 객체 복사란 무엇이며, clone() 메소드를 통한 클로닝과 생성자를 통한 복사의 차이점은 무엇이며, 각각의 방법을 어떤 경우에 사용해야 할까요?

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

답변.

자바에서 객체 복사는 기존의 인스턴스와 동일한 상태를 가진 새로운 객체를 생성하는 과정입니다. 역사적으로 객체를 수동으로 다시 생성하지 않고 복제해야 할 필요성이 제기되면서 자바의 초기 발전 단계에서 이 복사 개념이 등장했습니다. 자바는 객체 복사를 위한 보편적인 방법을 제공하지 않으며, 대신 clone() 계약과 복사 생성자 패턴을 사용합니다.

문제의 역사

clone() 메소드는 객체 클로닝을 위한 표준 메커니즘을 제공하기 위해 Cloneable 인터페이스에 도입되었으나, 그 구현은 많은 뉘앙스를 제공하며 종종 버그를 발생시킵니다.

문제

주요 문제는 "상자 속"에서 진정한 깊은 복사가 없고, 얕은 클로닝(shallow copy) 시 예측할 수 없는 행동이 발생할 가능성입니다. 복사 생성자는 얕은 복사와 깊은 복사를 모두 구현할 수 있지만 명시적인 구현이 필요합니다.

해결책

복잡한 객체를 안전하고 올바르게 복사하려면 복사 생성자 또는 팩토리 메소드를 사용하는 것이 더 좋으며, clone()은 객체가 이 계약에 실제로 적합한 경우에만 주의해서 사용하는 것이 좋습니다.

코드 예시:

// clone()을 통한 얕은 복사 public class Address implements Cloneable { String city; public Address(String city) { this.city = city; } @Override public Address clone() throws CloneNotSupportedException { return (Address) super.clone(); } } public class Person implements Cloneable { String name; Address address; public Person(String name, Address address) { this.name = name; this.address = address; } @Override public Person clone() throws CloneNotSupportedException { Person copy = (Person) super.clone(); copy.address = address.clone(); // 깊은 복사 address return copy; } } // 복사 생성자 public class Person { String name; Address address; public Person(Person other) { this.name = other.name; this.address = new Address(other.address.city); } }

주요 특징:

  • clone()Cloneable 인터페이스의 구현과 clone 메소드의 재정의를 요구합니다.
  • 얕은 복사는 참조만 복사하고, 객체는 복사하지 않습니다.
  • 복사 생성자는 복사의 깊이와 예외 처리를 완벽하게 제어할 수 있습니다.

함정 질문.

질문 1: 클래스가 Cloneable을 구현하지 않으면 clone()을 호출할 때 어떤 일이 발생합니까?

clone()은 객체가 Cloneable 인터페이스를 구현하지 않으면 CloneNotSupportedException을 던집니다.

질문 2: clone()을 통한 클로닝은 기본적으로 깊은 복사인가요?

아니요, 기본적으로 얕은 클로닝만 구현되며, 모든 객체에 대한 참조는 그대로 복사됩니다.

질문 3: 깊은 클로닝을 위해 복사 생성자를 사용하지 않고도 될까요?

아니요, 프로세스를 제어하려면 명시적으로 생성자를 통해 내부 객체들을 복사하거나 clone()에서 수동으로 구현해야 합니다.

일반적인 오류 및 안티 패턴

  • 변경 가능한 참조 필드를 가진 객체에 대한 얕은 클로닝 사용
  • super.clone을 호출하지 않음으로써 clone 계약 위반
  • 예외 처리가 없고 Cloneable을 구현하지 않아 클로닝이 불가능함

실생활 사례

부정적 사례

개발자가 List<Product> 필드를 가진 Order 클래스에서 표준 clone()을 적용했습니다. 그 결과 복사본에서 제품 목록을 변경하면 원본의 제품도 변경되어 버그가 발생했습니다.

장점:

  • 적은 코드.
  • 간단한 객체의 빠른 클로닝.

단점:

  • 변경 가능한 필드를 가진 객체 복사 시 심각한 버그.
  • 클로닝 프로세스에 대한 통제 상실.

긍정적 사례

회사는 모든 도메인 엔티티에 대해 복사 생성자를 구현하고, 복잡한 중첩 객체의 클로닝 프로세스에 대한 테스트를 추가했습니다.

장점:

  • 복사에 대한 완전한 제어.
  • 예상치 못한 부작용 없음.

단점:

  • 코드량 증가.
  • 클래스 구조 변경 시 생성자 지원 필요.