Java Cloneable
에 대해 설명하는 자습서를 찾고 있었지만 좋은 링크를 얻지 못했으며 어쨌든 Stack Overflow가 더 분명한 선택이되고 있습니다.
다음을 알고 싶습니다.
Cloneable
Cloneable
인터페이스 를 구현하여 객체의 복제본이나 사본을 가질 수 있음을 의미합니다 . 그렇게하는 것의 장점과 단점은 무엇입니까?- 오브젝트가 복합 오브젝트 인 경우 재귀 복제는 어떻게 발생합니까?
Java Cloneable
에 대해 설명하는 자습서를 찾고 있었지만 좋은 링크를 얻지 못했으며 어쨌든 Stack Overflow가 더 분명한 선택이되고 있습니다.
다음을 알고 싶습니다.
Cloneable
Cloneable
인터페이스 를 구현하여 객체의 복제본이나 사본을 가질 수 있음을 의미합니다 . 그렇게하는 것의 장점과 단점은 무엇입니까? 답변:
가장 먼저 알아야 할 것은 Cloneable
-사용하지 마십시오.
Cloneable
올바른 복제를 구현하는 것은 매우 어렵고 노력할 가치가 없습니다.
대신 apache-commons SerializationUtils
(딥 클론) 또는 BeanUtils
(shallow-clone) 과 같은 다른 옵션을 사용 하거나 단순히 복사 생성자를 사용하십시오.
Cloneable
접근 방식의 많은 단점을 설명 하는를 사용한 복제에 대한 Josh Bloch의 견해를 보려면 여기 를 참조하십시오 . ( Joshua Bloch 는 Sun 직원이었으며 수많은 Java 기능 개발을 이끌었습니다.)
static
인터페이스에 메소드를 가질 수 있으므로 static WhatEverTheInterface copy(WhatEverTheInterface initial)
? 하지만 복제하는 동안 개체에서 필드를 복사하기 때문에 이것이 무엇을 제공하는지 궁금합니다. 그러나 인터페이스는 메서드 만 정의합니다. 설명할까요?
Cloneable 자체는 불행히도 마커 인터페이스 일뿐입니다. 즉, clone () 메서드를 정의하지 않습니다.
하는 일은 보호 된 Object.clone () 메서드의 동작을 변경하는 것입니다.이 메서드는 Cloneable을 구현하지 않는 클래스에 대해 CloneNotSupportedException을 throw하고이를 수행하는 클래스에 대해 멤버 단위 얕은 복사를 수행합니다.
이것이 당신이 찾고있는 행동이라 할지라도, 당신은 그것을 공개하기 위해 자신 만의 clone () 메소드를 구현해야 할 것입니다.
자신의 clone ()을 구현할 때 아이디어는 super.clone ()에 의해 생성 된 객체로 시작하여 올바른 클래스임을 보장 한 다음 얕은 사본이 아닌 경우 추가 필드 채우기를 수행하는 것입니다. 당신이 원합니다. clone ()에서 생성자를 호출하면 하위 클래스가 자신의 추가 복제 가능한 논리를 추가하려는 경우 상속이 중단되므로 문제가 될 수 있습니다. super.clone ()을 호출하면이 경우 잘못된 클래스의 객체를 얻게됩니다.
이 접근 방식은 생성자에 정의 될 수있는 모든 논리를 우회하므로 잠재적으로 문제가 될 수 있습니다.
또 다른 문제는 clone ()을 재정의하는 것을 잊은 모든 하위 클래스가 기본 얕은 복사본을 자동으로 상속한다는 것입니다. 이는 변경 가능한 상태 (이제 소스와 복사본간에 공유 됨)의 경우 원하는 것이 아닐 가능성이 높습니다.
대부분의 개발자는 이러한 이유로 Cloneable을 사용하지 않고 대신 복사 생성자를 구현합니다.
Cloneable에 대한 자세한 정보와 잠재적 인 함정에 대해서는 Joshua Bloch의 Effective Java 책을 적극 권장합니다.
따라서 Cloneable을 신중하게 사용하십시오. 모든 일을 올바르게하기 위해 신청해야하는 노력에 비해 충분한 혜택을주지는 않습니다.
복제는 기본 프로그래밍 패러다임입니다. Java가 여러 가지 방법으로 제대로 구현하지 않았을 수 있다는 사실이 복제 필요성을 전혀 줄이지 않습니다. 또한 원하는대로 얕고 깊고 혼합 된 방식으로 작동하는 복제를 쉽게 구현할 수 있습니다. 원하는 경우 Cloneable을 구현하지 않고 함수에 복제 이름을 사용할 수도 있습니다.
A, B 및 C 클래스가 있다고 가정합니다. 여기서 B와 C는 A에서 파생됩니다. 다음과 같은 A 유형의 개체 목록이있는 경우 :
ArrayList<A> list1;
이제이 목록에는 A, B 또는 C 유형의 개체가 포함될 수 있습니다. 개체가 어떤 유형인지 알 수 없습니다. 따라서 다음과 같이 목록을 복사 할 수 없습니다.
ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
list2.add(new A(a));
}
개체가 실제로 B 또는 C 유형이면 올바른 복사본을 얻을 수 없습니다. 그리고 A가 추상적이라면? 이제 어떤 사람들은 이것을 제안했습니다.
ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
if(a instanceof A) {
list2.add(new A(a));
} else if(a instanceof B) {
list2.add(new B(a));
} else if(a instanceof C) {
list2.add(new C(a));
}
}
이것은 아주, 아주 나쁜 생각입니다. 새로운 파생 유형을 추가하면 어떻게됩니까? B 또는 C가 다른 패키지에 있고이 클래스에 액세스 할 수없는 경우 어떻게합니까?
당신이하고 싶은 것은 이것입니다 :
ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
list2.add(a.clone());
}
많은 사람들이 복제의 기본 Java 구현이 문제가되는 이유를 지적했습니다. 그러나 다음과 같이 쉽게 극복 할 수 있습니다.
클래스 A :
public A clone() {
return new A(this);
}
클래스 B :
@Override
public B clone() {
return new B(this);
}
클래스 C :
@Override
public C clone() {
return new C(this):
}
동일한 함수 이름을 사용하여 Cloneable을 구현하지 않습니다. 마음에 들지 않으면 다른 이름을 지정하십시오.
Cloneable의 단점은 무엇입니까?
복제하는 객체에 컴포지션이있는 경우 복제는 매우 위험합니다. 복제는 얕은 복사본을 생성하기 때문에이 경우 가능한 부작용을 아래에서 고려해야합니다.
db 관련 조작을 처리 할 하나의 개체가 있다고 가정 해 보겠습니다. 객체가 Connection
속성 중 하나로 객체를 가지고 있다고 가정 합니다.
따라서 누군가가의 복제본을 originalObject
만들 때 생성 되는 개체는 cloneObject
. 여기 originalObject
및 cloneObject
대해 동일한 참조 보유 Connection
개체.
말을하자 originalObject
닫히고에게 Connection
개체를, 그래서 지금 cloneObject
때문에하지 않습니다 작업 connection
개체가 그들 사이에 공유되고이 actaually에 의해 폐쇄되었다 originalObject
.
IOStream을 속성으로 갖는 객체를 복제하려는 경우에도 유사한 문제가 발생할 수 있습니다.
오브젝트가 복합 오브젝트 인 경우 재귀 복제는 어떻게 발생합니까?
Cloneable은 얕은 복사를 수행합니다. 의미는 원본 개체와 복제 개체의 데이터가 동일한 참조 / 메모리를 가리킬 것입니다. 반대로 딥 카피의 경우 원본 오브젝트의 메모리에있는 데이터가 복제 오브젝트의 메모리로 복사됩니다.
Cloneable
복사 Object.clone
하지 않습니다. "원래 개체의 메모리에있는 데이터가 복제 개체의 메모리에 복사됩니다"가 정확히하는 일 Object.clone
입니다. 깊은 복사를 설명하기 위해 참조 된 객체의 메모리에 대해 이야기해야합니다.