Java에서 인스턴스의 딥 클론 / 복사를 수행하는 권장 방법이 있는지 궁금합니다.
나는 3 가지 해결책을 염두에두고 있지만 일부를 놓칠 수 있으며 귀하의 의견을 듣고 싶습니다
편집 : Bohzo propositon을 포함시키고 질문을 수정하십시오 : 얕은 복제보다는 깊은 복제에 관한 것입니다.
스스로 해:
속성 다음에 수동으로 복제 속성을 코딩하고 변경 가능한 인스턴스도 복제되는지 확인하십시오.
pro :
-수행 할 작업 제어
-빠른 실행
단점 :
-작성 및 유지 관리가 지루합니다
.-버그가 발생하기 쉽습니다 (복사 / 붙여 넣기 실패, 속성 누락, 변경 가능한 속성 재 지정)
반사 사용 :
자체 리플렉션 도구 또는 자카르타 커먼 빈과 같은 외부 도우미를 사용하면 한 줄로 작업을 수행하는 일반적인 복사 방법을 쉽게 작성할 수 있습니다.
pro :
-작성하기 쉬움
-유지 보수
불필요 :
-발생 제어력 감소
-리플렉션 도구가 하위 오브젝트도 복제하지 않는 경우 가변 오브젝트로 버그가 발생하기 쉬움
-실행 속도 저하
복제 프레임 워크를 사용하십시오.
다음과 같은 프레임 워크를 사용하십시오.
commons-lang SerializationUtils
Java Deep Cloning Library
Dozer
Kryo
pro :
-리플렉션과 동일
-정확하게 복제 될 대상에 대한 더 많은 제어
단점 :
-모든 가변 인스턴스는 계층 구조의 끝에서도 완전히 복제
됩니다. 실행 속도가 매우 느릴 수 있습니다.
런타임에 바이트 코드 계측을 사용하여 복제본 작성
javassit , BCEL 또는 cglib를 사용하면 한 손으로 작성하는 것만 큼 빠른 전용 복제기 를 생성 할 수 있습니다. 누군가이 목적을 위해 이러한 도구 중 하나를 사용하여 lib를 알고 있습니까?
내가 여기서 놓친 것?
어느 것을 추천 하시겠습니까?
감사.
답변
딥 클로닝 (전체 객체 계층 구조 복제) :
-
commons-lang SerializationUtils-직렬화 사용-모든 클래스가 제어하고 강제로 구현할 수있는 경우
Serializable
. -
Java Deep Cloning Library- 리플렉션 사용-복제하려는 클래스 또는 객체가 제어 할 수없는
Serializable
경우 (타사 라이브러리)이를 구현할 수 없거나 구현 하고 싶지 않은 경우Serializable
.
얕은 복제 (첫 번째 수준 속성 만 복제) :
-
commons-beanutils BeanUtils- 대부분의 경우.
-
Spring BeanUtils- 이미 스프링을 사용하고 있으므로 클래스 경로에이 유틸리티가있는 경우
“자신에게 할 일”옵션을 의도적으로 생략했습니다. 위의 API는 무엇을 복제하지 않을지 (예 : transient
, 또는 String[] ignoreProperties
) 를 잘 제어 할 수 있으므로 휠을 다시 만드는 것은 바람직하지 않습니다.
답변
Joshua Bloch의 책에는 “항목 10 : 복제를 신중하게 재정의하십시오” 라는 제목의 전체 장이 있습니다 . 있으며 대부분의 경우 복제를 재정의하는 것이 나쁜 생각 인 이유에 대해 설명합니다.
그는 몇 가지 대안을 제공합니다.
-
생성자 대신 팩토리 패턴을 사용하십시오.
public static Yum newInstance(Yum yum);
-
복사 생성자를 사용하십시오.
public Yum(Yum yum);
Java의 모든 컬렉션 클래스는 복사 생성자를 지원합니다 (예 : new ArrayList (l);)
답변
버전 2.07부터 Kryo는 얕고 깊은 복제를 지원합니다 .
Kryo kryo = new Kryo();
SomeClass someObject = ...
SomeClass copy1 = kryo.copy(someObject);
SomeClass copy2 = kryo.copyShallow(someObject);
Kryo는 빠르며 페이지에서 생산에 사용하는 회사 목록을 찾을 수 있습니다.
답변
메모리에서 XStream toXML / fromXML을 사용하십시오. 매우 빠르며 오랫동안 주변에 있었고 강세를 보이고 있습니다. 객체는 직렬화 가능하지 않아도되며 리플렉션을 사용할 필요가 없습니다 (XStream이 그렇더라도). XStream은 동일한 객체를 가리키는 변수를 식별 할 수 있으며 실수로 인스턴스의 전체 사본을 두 개 만들지 않습니다. 그와 같은 많은 세부 사항이 수년에 걸쳐 나왔습니다. 나는 그것을 몇 년 동안 사용해 왔으며 그것이 가고 있습니다. 상상할 수있는만큼 사용하기 쉽습니다.
new XStream().toXML(myObj)
또는
new XStream().fromXML(myXML)
복제하려면
new XStream().fromXML(new XStream().toXML(myObj))
간결하게 :
XStream x = new XStream();
Object myClone = x.fromXML(x.toXML(myObj));
답변
복잡한 객체의 경우 성능이 중요하지 않은 경우 gson
을 사용 하여 객체를 json 텍스트로 직렬화 한 다음 텍스트를 직렬화 해제하여 새 객체를 가져옵니다.
리플렉션을 기반으로하는 gson은 transient
필드가 복사되지 않고 순환 참조가있는 객체 인 cause를 제외하고 대부분의 경우 작동합니다 StackOverflowError
.
public static <ObjectType> ObjectType Copy(ObjectType AnObject, Class<ObjectType> ClassInfo)
{
Gson gson = new GsonBuilder().create();
String text = gson.toJson(AnObject);
ObjectType newObject = gson.fromJson(text, ClassInfo);
return newObject;
}
public static void main(String[] args)
{
MyObject anObject ...
MyObject copyObject = Copy(o, MyObject.class);
}
답변
다릅니다.
속도를 높이려면 DIY를 사용하십시오. 방탄을 위해 반사를 사용하십시오.
BTW, 직렬화는 refl과 동일하지 않습니다. 일부 객체는 재정의 된 직렬화 메소드 (readObject / writeObject)를 제공 할 수 있고 버그가있을 수 있습니다.
답변
좋은 hashCode () 및 equals () 메소드와 결합 된 단위 방식으로 쉽게 증명할 수있는 DIY 방법을 권장합니다.