2010-03-11 3 views
115

복제 메소드와 java의 복사 생성자. 어느 것이 올바른 해결책인가. 어디에서 각 경우를 사용합니까?Clone() vs 복사 생성자 - Java에서 권장되는

+6

http://stackoverflow.com/questions/1106102/clone-vs-copy-constructor-vs-factory-method –

+3

'복제본 * *'을 사용하지 마십시오. 아무리해도 * 자신의 사본 솔루션을 찾으십시오. – dimitarvp

+0

복사 생성자가 Object보다 낫습니다.왜냐하면 그들은 우리가 어떤 인터페이스를 구현하도록 강요하지 않거나 예외를 던지지 만, 우리가 반드시해야한다면 그것을 수행 할 수 있습니다. 캐스트가 필요하지 않습니다. 알려지지 않은 객체에 의존하지 않아도됩니다. 부모 클래스가 어떤 계약을 따르거나 아무것도 구현하지 않아도됩니다. 최종 필드 수정 허용, 객체 생성을 완전히 제어 할 수있게하고 초기화 논리를 작성할 수 있습니다. 더 읽기 https://programmingmitra.blogspot.in/2017/01/Java-cloning-copy-constructor-versus-Object-clone-or-cloning.html –

답변

90

복제가 손상되었으므로 사용하지 마십시오. 그것은 그 개체의 동일한 복사본을 생성하지 :

Object 클래스 의 clone 메소드는 할 이제까지 수없는 순수 자바 방법은 무엇 을하는 다소 마법의 방법이다. Java 컴파일러 *의 베타 - 릴리스 날짜 이후 원시 객체 슈퍼 클래스에있었습니다. 그리고, 모든 고대 마법처럼, 사본 오브젝트

Foo copyFoo (Foo foo){ 
    Foo f = new Foo(); 
    //for all properties in FOo 
    f.set(foo.get()); 
    return f; 
} 

읽기 예기치 않게

이 방법을 선호 역효과 에서 주문을 방지하기 위해 적절한 주문을 필요로 더 http://adtmag.com/articles/2000/01/18/effective-javaeffective-cloning.aspx

+18

음, 복제가 손상되지 않았습니다. 왜 그렇게 생각하니? 그것을 덮어 씌우지 않으면 작동하지 않기 때문입니다 - 음, 그 계약입니다. – Bozho

+23

@Bozho, Effective Java 2 판 _을 읽어보십시오. Bloch는 아주 잘 설명했습니다. Doug Lea는 배열 복제 (http://www.artima.com/intv/bloch13.html)를 제외하고는 더 이상'clone()'을 사용하지 않습니다. – polygenelubricants

+1

왜 복제가 더 간단하지 않을 수 있는지 이해가되지 않습니다. 이것이 선택인가? 아니면 일반적인 경우에 그 뒤에 정말 가혹한 문제가 있습니까? – LB40

47

clone()은 기본적으로 작동하지 않는다는 것을 명심하십시오. Cloneable을 구현하고 clone() 메서드를 public에서 재정의해야합니다.

바람직하다 몇 가지 대안이있다합니다 (clone() 방법은 다른 답변에 명시된 바와 같이 설계 문제를 많이 가지고 있기 때문에)와 복사 생성자는 수동 작업이 필요합니다 :

+1

딥 클론 라이브러리는 어떤 객체에서 어떻게 작동합니까? 나는 아마 반사와 함께 수수께끼의 코드 냄새가 – Cruncher

+0

예, 많은 반사 :) – Bozho

+0

이들 중 어느 것도 참조를 복사하지 않고 값으로 복사합니까? BeanUtils.cloneBean (bean)은 참조를 복사하고 있지만 원래 Apache 버전이 아닌 android 버전 (android-java-air-bridge.jar)을 사용하고 있습니다. –

3

페이지를 구현할 필요없이 깊은 복제를 제공합니다 구현해야합니다 : How to properly override clone method?. 클로닝은 Java에서 깨졌습니다. 이므로 매우 어렵습니다.을 사용하면 올바르게 처리 할 수 ​​있습니다. 심지어 은 실제로 많이 제공하지 않습니다.이므로 번거 로움이 없습니다.

+0

'java.lang.Object'에서 상속받은'final' 클래스가있을 때 훨씬 쉽게 얻을 수 있습니다. 클래스가 변경 가능한 데이터 구조를 포함하므로 (따라서 딥 카피가 필요함) 까다로운 일이지만, 동일한 도전이 복사 생성자에도 나타날 수 있습니다. – IceArdor

18

복사 생성자는 클래스 형식을 복사 생성자의 형식으로 제한합니다. 예를 생각해

// Need to clone person, which is type Person 
Person clone = new Person(person); 

이것은 personPerson의 서브 클래스를 할 수 있다면 작업 (또는 Person가 인터페이스 인 경우)하지 않습니다. 이것은 복제본의 전체 요점입니다. 즉, 런타임에 적절한 유형을 동적으로 복제 할 수 있다는 것입니다 (복제가 제대로 구현되었다고 가정).

Person clone = (Person)person.clone(); 

또는

Person clone = (Person)SomeCloneUtil.clone(person); // See Bozho's answer 

지금 personclone가 제대로 구현되는 것을 가정 Person의 모든 유형이 될 수 있습니다.

+0

'clone '의 적절한 행동은 그 메소드 자체가'super.clone()'을 호출하는 것이기 때문에 누군가가 한 번 복제의 적절한 구현이'super.clone()'보다는'new'를 포함해야한다고 제안한 것은 유감스러운 일입니다. 'super.clone()'을 호출한다 (또는 객체를위한 내장 된 멤버 별 복제이다). 'super.clone()'이'new' 호출을 끝내면'clone()'의 완전히 완전히 깨진 동작은'new' 자체를 호출하는 것뿐입니다. 그러나 모든 자식 클래스는'clone()'을 자식 클래스가'clone()'을 오버라이드 (override) 할 필요가 있을지 어떨지를 마찬가지로 행한다. – supercat

+0

"deep vs shallow"질문은 대부분의 경우 나에게 모호하지 않은 것처럼 보입니다. 'SomeCollection '은'T' 타입의 것들의 * identity *를 유지하기 위해 존재하며,'clone()'을 호출하면 원본과 분리 된 동일한 유형의 새로운 인스턴스를 생성해야하지만 동일한 인스턴스에 대한 참조를 보유합니다 'T'입니다.원본 또는 복제본에 수행 할 수있는 작업은 다른 개체에 저장된 개체의 * ID *에 영향을주지 않습니다. 나는 혼란이 무엇인지 이해하지 못한다. – supercat

30

clone()은 여러 실수 (this question 참조)로 설계되었으므로 피하는 것이 가장 좋습니다. Effective Java 2nd Edition에서

, 항목 11 : 재정의 클론 신중

Cloneable을과 관련된 모든 문제, 그것은 다른 인터페이스를 확장하지 않도록 말을 안전하고 감안할 때 상속을 위해 설계된 클래스 (항목이 17)는 그것을 구현해서는 안됩니다. 의 많은 단점으로 인해 일부 전문가 프로그래머는 을 복제 방법을 재정의하지 않고 단순히 복사 배열 을 제외하고는 절대로 호출하지 않기로 선택합니다. 상속을위한 클래스를 디자인하는 경우 잘 작동하는 보호 된 복제 메서드를 제공하지 않기로 선택하면 은 하위 클래스에서 Cloneable을 구현할 수 없습니다.

이 설명서에서는 복사 생성자가 Cloneable/clone보다 갖는 많은 장점에 대해서도 설명합니다. 그들은 위험 발생하기 쉬운 extralinguistic 객체 생성 메커니즘에 의존하지 않는

  • 그들은 마지막 필드
  • 을의 적절한 사용과 충돌하지 않는
  • 얇게 문서화 된 규칙을 집행 준수를 요구하지 않습니다
  • 불필요한 확인 예외를 throw하지 않습니다.
  • 캐스팅이 필요하지 않습니다.

모든 표준 컬렉션에는 복사 생성자가 있습니다. 그것을 써.

List<Double> original = // some list 
List<Double> copy = new ArrayList<Double>(original); 
+3

'원본'을 다른 유형의 목록 (예 :'LinkedList ')으로 사용했을 때'ArrayList'로 복사하고 있습니다. 이것은 복제가 복사 생성자보다 나은 이유입니다. –

2

큰 슬픔 : Cloneable를/복제 나 생성자도 훌륭한 솔루션입니다 : 내가 구현 클래스를 알고 싶지 않아! (예 : - 동일한 숨겨진 MumbleMap 구현을 사용하여 복사 할지도가있는지도가 있습니다.) 지원되는 경우 사본을 만들고 싶습니다. 그러나 Cloneable에는 clone 메서드가 없으므로 clone()을 호출 할 때 안전하게 형변환 할 수있는 것이 없습니다.

오라클은 최상의 "Copy Object"라이브러리가 무엇이든 관계없이 Oracle을 다음 Java 릴리스의 표준 구성 요소로 설정해야합니다 (아직 숨겨져 있지 않은 경우).

물론 더 많은 라이브러리 (예 : 컬렉션)가 변경 불가능한 경우이 '복사'작업은 사라집니다. 그런 다음 우리는 "빈"패턴보다는 "클래스 불변성"과 같은 것들을 사용하여 Java 프로그램을 설계하기 시작할 것입니다 (깨진 객체를 만들고 좋은 것으로 바뀔 때까지 변형).

+0

프로젝트에서 만드는 값 객체에 대해서는 최소한 다음과 같은 몇 가지 희망이 있습니다. https://projectlombok.org/features/experimental/Wither.html – Roboprog

+0

복사가 쉽다면 이미 가질 것입니다. Java의 일부입니다. 그러나 그렇지 않습니다. 너는 얕은 사본, 깊은 사본, 또는 그 중간 어딘가에 원하는가? 복사하는 대상과 캐스팅 대상에 따라 수업마다 다른 행동을 취하고 있습니까? Generics는 어떻게됩니까? 복사중인 내용이 일반용 매개 변수 일 때 어떤 일이 발생합니까? 이것은 상속없이 변경이 불가능한 이유로 조금 더 쉽게 생각할 수 있지만 Java (언어)의 핵심으로 구워집니다. 어쩌면 가변성을 보장하는 Scala와 같은 언어는 복제 가능성을 더 쉽게 만듭니다. – IceArdor