이 기사에서는 다음 4 가지 문제에 대해 설명합니다
1. Java 클로닝 가능한 인터페이스는 딥 카피를 구현합니다
2. Java 직렬화는 딥 카피를 구현합니다
3. 가장 빠른 딥 카피 바이너리 라이브러리 복제 소스 코드 분석
4. 여러 카피 방법의 속도 비교
이 기사에서 딥 카피의 개념에 대해서는 이야기하지 않을 것입니다. C ++에서 딥 카피 구현. 일반적으로 과제 연산자 "="에 과부하가 발생하여 동일한 클래스의 객체간에 심층 사본을 구현하십시오. 따라서 Java에서는 기능 내에서 객체의 각 속성을 할당하는 사본 함수를 정의 할 수 있습니다. 이 방법은 단순하고 자연 스럽지만 치명적인 문제가 있습니다. 언젠가 딥 카피가 필요한 새로운 속성이 클래스에 추가되면 해당 복사 기능도 수정해야합니다. 이 방법은 클래스의 확장성에 큰 불편 함을 가져옵니다. 이 문제를 해결하는 방법, 1 장, 2 장 및 3 장의 구현 방법과 섹션 4의 속도 테스트를 살펴 보겠습니다.
1. Java 클로닝 가능한 인터페이스는 딥 카피 <br />를 구현합니다. 이 방법으로 클래스는 colnable 인터페이스 복제 기능을 구현하고 클론 기능에서 Super.Clone을 호출해야합니다. 이 방법의 딥 카피는 또 다른 문제를 가져옵니다. 클래스의 속성으로 다른 클래스의 객체가있는 경우 다른 클래스도 클로닝 가능한 인터페이스에서 과부하 및 구현해야합니다. 여기 예입니다. 다음 예에서는 ComplexDO에는 단순한 물체가 포함되어 있습니다. Complexdo Deep Copy를 구현하려면 먼저 Simpledo의 클론 인터페이스를 구현해야합니다.
공개 클래스 Simpledo는 복제 가능, 직렬화 가능한 {private int x = 1; 개인 문자열 s = "simpledo"; @override Protected Object Clone ()는 ClonenotsupportedException {simpledo newclass = (simpledo) super.clone (); 뉴 클래스를 반환하십시오. }} public class complexdo는 복제 가능, 직렬화 가능한 {private int x = 1; 개인 문자열 s = "복잡한"; 개인 정수 A = 123; 개인 정수 B = 1234; 개인 정수 C = 1334455; 개인 문자열 s2 = "hehehe"; 개인 문자열 s3 = "hahaha"; 개인 긴 ID = 1233245L; private arraylist <simpledo> l = new arraylist <simpledo> (); @override public Object Clone ()는 clonenotsupportedexception {complexdo newclass = (Complexdo) super.clone (); newclass.l = new Arraylist <simpledo> (); for (simpledo simple : this.l) {newclass.l.add ((simpledo) simple.clone ()); } return newClass; }} 많은 기사에서 문자열 유형의 과제 연산자는 딥 카피라고 말하지만 실제로 Java에서 할당 연산자를 사용하는 사람들은 얕은 사본이지만, 왜 그런 명백한 오류가있는 기사가 이것이 딥 카피라고 말해야합니까? 내 이해는 문자열과 유형 속성이 기본 유형이며, 제공된 방법은 내부 데이터 변경이 설계되는 한 새로운 객체가됩니다. 따라서 문자열 작동은 원래 지적한 메모리에 영향을 미치지 않습니다. 따라서 일반적으로 문자열과 같은 기본 클래스의 할당 작업은 깊은 사본입니다.
이러한 이유로 문자열 문자열 스 플라이 싱을 사용할 때 새 메모리를 열어야하므로 많은 사람들이 스 플라이 싱을 위해 문자열 대신 StringBuilder를 사용하는 것이 좋습니다. StringBuilder는 내장형 Charray 범위가 충분하지 않을 때 더 큰 메모리를 다시 적용 할 수 있기 때문에 (현대식 JVM의 경우, 코드가 조정되고 String+String은 StringBuilder.Append)에 대해 유사한 명령어로 최적화됩니다. 스 플라이 싱과 반대되는 자르기 위해서는 문자열에 서브 스트링 함수가 있습니다. 기판 함수를 사용할 때 새 문자열의 내부 숯 배열이 원래 문자열과 동일합니까? 이것은 더 흥미 롭습니다. 관심이 있으시면 JDK1.6 및 JKD1.7의 구현을 비교하고 확인할 수 있습니다.
2. Java 직렬화는 딥 카피를 구현합니다
이 방법의 원칙은 Java 직렬화를 사용하여 객체를 이진 바이트 스트림으로 직렬화 한 다음 객체를 객체에 버리고 할당하는 것입니다. Code example:
public object seircopy (object src) {try {bytearrayoutputStream byteout = new BytearRayoutputStream (); ObjectOutputStream out = 새로운 ObjectOutputStream (바이트 아웃); out.writeObject (SRC); bytearrayinputStream bytein = new bytearrayinputstream (byteout.tobytearray ()); ObjectInputStream in = New ObjectInputStream (Bytein); Object dest = in.readobject (); 반환 데스트; } catch (예외 e) {// 일부 오류 핸들러를 반환합니다. }} 물론 JSON 및 기타 직렬화 된 라이브러리를 사용하여 직렬화를 완료 할 수도 있습니다. 이 방법은 클로닝 인터페이스의 확장 가능한 단점을 효과적으로 피합니다. 함수는 기본적으로 모든 클래스에 적합 할 수 있습니다. 단점은 상대 메모리 사본이라는 것입니다. 직렬화는 먼저 물체를 이진 바이트 스트림으로 변환 한 다음 바이너리 바이트 스트림을 객체 메모리 조각으로 재구성하는 데 조화를 이루어야하며, 이는 비교적 느립니다.
3. 가장 빠른 딥 카피 바이너리 라이브러리 복제 소스 코드 분석
소스 코드에서 핵심 처리 로직은 Cloner 클래스에 있습니다.
두 가지 재귀 링크가 있습니다.
(1)에서, Fastclone은 ifastclone 인터페이스 클래스에서 상속 된 객체를 완성합니다. 즉, 모두 컬렉션 작업의 사본입니다.
(2)에서, cloneobject는 반사 메커니즘을 통해 정상 객체의 각 속성을 얻는 프로세스를 완료 한 다음 objenesis를 사용하여 새로 생성 된 물체의 특성에 값을 할당합니다.
이 방법은 확장 가능합니다. 기존 코드에 의존하여 깊은 복사를 완료 할 수있을뿐만 아니라 클로닝이 필요하지 않은 일부 복제 방법과 유형을 정의 할 수도 있습니다.
4. 여러 카피 방법의 속도 비교
위의 세 가지 모드는 깊은 복사를 완료하는 데 사용될 수 있으며 가장 빠른 복사 방법은 우리가 관심을 갖는 것입니다.
먼저 코드를 테스트하십시오.
public void testclonecomplex ()는 clonenotsupportedException {최종 int copycount = 1; 목록 <complexdo> complexdolist = new arraylist <complexdo> (CopyCount * 3); 최종 Complexdo Complex = New Complexdo (); // 양측 라이브러리 계산 Long Start = System.CurrentTimeMillis (); for (int i = 0; i <CopyCount; ++ i) {Final Complexdo DeepClone = clner.deepclone (complex); complexdolist.add (딥 클론); } long end = System.CurrentTimeMillis (); System.out.println ( "딥 클론 비용 시간 =" + (종료 시작)); // 복제 가능한 인터페이스에서 구현 한 클론 함수를 호출 시작 = System.CurrentTimeMillis (); for (int i = 0; i <CopyCount; ++ i) {Final Complexdo interfaceclone = (Complexdo) Complex.Clone (); complexdolist.add (interfaceclone); } end = System.CurrentTimeMillis (); System.out.println ( "interfaceclone 비용 시간 =" + (종료 시작)); // 직렬화 및 사제화 새로운 객체 시작 = System.CurrentTimeMillis (); for (int i = 0; i <CopyCount; ++ i) {Final Complexdo Seirclone = Seircopy (복합체); complexdolist.add (seirclone); } end = System.CurrentTimeMillis (); System.out.println ( "Seirclone Cost Time =" + (end-Start)); }실행 결과 단위는 밀리 초입니다 (이 데이터는 무시되며 Java 핫스팟 및 가능한 GC를 계산하지 않습니다).
이 표에서 우리는 다음과 같은 결론을 도출 할 수 있습니다.
1. 클로닝 가능한 인터페이스의 복사는 메모리 사본 만 포함되기 때문에 가장 빠르지 만 관련된 속성이 더 일반적인 개체 인 경우 작성하는 것이 약간 번거 롭습니다.
2. 직렬화/사막화 사본은 가장 느립니다
3. 클로닝 라이브러리를 사용하여 재귀 및 반사 메커니즘의 복사는 클로닝 가능한 인터페이스 구현보다 느리지 만 직렬화 방법보다 빠릅니다.
위의 내용은이 기사에 관한 모든 것입니다. 모든 사람의 학습에 도움이되기를 바랍니다.