공식적으로 주제를 입력하기 전에 먼저 딥 카피와 사전 코피의 개념을 이해해 봅시다.
라이트 카피 :
원래 오브젝트의 속성 값의 정확한 사본이있는 새 개체가 생성됩니다. 속성이 기본 유형 인 경우 기본 유형의 값이 복사됩니다. 속성이 메모리 주소 인 경우 메모리 주소가 복사되므로 객체 가이 주소를 변경하면 다른 객체에 영향을 미칩니다.
딥 카피 :
객체의 모든 참조되지 않은 멤버 변수 값을 복사 할뿐만 아니라 참조 유형의 멤버 변수에 대한 새 인스턴스를 만들고 공식 매개 변수 인스턴스 값으로 초기화해야합니다.
개념을 이해 한 후 일반 객체 할당 작업이 딥 카피인지 얕은 사본인지 테스트 해 보겠습니다.
테스트 코드 :
Public Class Devthcopy {public static void main (String [] args) {copy first = new Cop ( "hzw", 24); 두 번째 복사 = 첫 번째; 두 번째 .name = "shanxi"; System.out.println (first.name); // output shanxi}} 클래스 사본 {public String name; 공개 int 연령; 공개 사본 (문자열 이름, int age) {this.name = name; this.age = age; }} Shanxi에 대한 이름 속성 값을 두 번째로 수정 한 후에는 이름 속성 값도 Shanxi가된다는 것을 알 수 있습니다. 이것은 일반적인 물체 할당이 얕은 사본에 속함을 보여줍니다.
물체 사이의 할당이 얕은 사본인지를 이해 한 후, 복제가 딥 카피인지 얕은 사본인지 확인해 봅시다. 테스트 코드는 위의 복사 객체가 클로닝 가능한 인터페이스에서 클론 메소드를 구현할 수 있도록하는 것입니다.
Public Class Devthcopy {public static void main (String [] args) {copy first = new Cop ( "hzw", 24); 복사 second = null; try {second = (copy) first.clone (); } catch (clonenotsupportedException e) {e.printstacktrace (); } second.name = "shanxi"; System.out.println (First.Name); // 출력 : hzw system.out.println (첫 번째); // output : com.hzw.day33.copy@7f39ebdb system.out.println (두 번째); // output : com.hzw.copy@33abb81e} class Copy emplestments inmplement emplest emplest}} 공개 int 연령; 공개 사본 (문자열 이름, int age) {this.name = name; this.age = age; } @Override Protected Object Clone ()는 ClonenOntSupportedException {return super.clone (); }}원래 생성 된 객체와 클로닝 된 객체 두 번째는 두 인스턴스이므로 두 번째 이름 속성의 수정은 첫 번째 이름 속성에 영향을 미치지 않습니다. 그러나 우리는 클로닝이 다음 예와 같은 딥 카피라고 생각할 수는 없습니다.
공공 계급 심도 {public static void main (String [] args) {학생 학생 = 신입생 (95); copy first = new Copy ( "HZW", 24, Student); 복사 second = null; try {second = (copy) first.clone (); } catch (clonenotsupportedException e) {e.printstacktrace (); } second.name = "shanxi"; 두 번째. 학생 .Score = 60; System.out.println (첫 번째 == 초); // false system.out.println (first.student == sucle.student); // true system.out.println (first.student.score); // 60}} 클래스 사본은 클로닝 가능 {public string 이름; 공개 int 연령; 공립 학생 학생; 공개 사본 (문자열 이름, int 연령, 학생 학생) {this.name = 이름; this.age = age; this.student = 학생; } @Override Protected Object Clone ()는 ClonenOntSupportedException {return super.clone (); }} 클래스 학생 {public int score; 공개 학생 (int score) {this.score = score; }}당신은 그것을 보셨습니까? 우리는 클로닝을 통해 두 번째를 만들었고, 첫 번째 == 두 번째 출력은 거짓이지만 첫 번째와 두 번째의 학생 객체는 동일하기 때문에 첫 번째와 두 번째가 두 인스턴스라는 것이 분명합니다. 학생의 점수 값을 2 초로 수정 한 후 첫 번째 학생의 점수도 변경되었습니다. 이것은 첫 번째와 두 번째 학생이 동일하다는 것을 의미합니다. 이것은 복제가 얕은 사본임을 의미합니다. 복제의 깊은 사본을 구현하려면 복사 대상의 학생 객체가 클로닝 가능한 인터페이스에서 복제 방법을 구현하고 복사의 복제 메소드는 학생의 클론을 반환하여 학생이 독특 할 수 있습니다. 수정 된 코드는 다음과 같습니다.
공공 계급 심도 {public static void main (String [] args) {학생 학생 = 신입생 (95); copy first = new Copy ( "HZW", 24, Student); 복사 second = null; try {second = (copy) first.clone (); } catch (clonenotsupportedException e) {e.printstacktrace (); } second.name = "shanxi"; 두 번째. 학생 .Score = 60; System.out.println (첫 번째 == 초); // false system.out.println (first.student == sucle.student); // false system.out.println (first.student.score); // 95 system.out.println (second.student.score); // 60}} 클래스 사본 클로즈 가능 공개 int 연령; 공립 학생 학생; 공개 사본 (문자열 이름, int 연령, 학생 학생) {this.name = 이름; this.age = age; this.student = 학생; } @Override Protected Object Clone ()는 ClonenOntSupportedException {copy = (copy) super.clone (); copy.student = (학생) Student.clone (); 반환 사본; }} 클래스 학생은 복제 가능한 {public int score; 공개 학생 (int score) {this.score = score; } @Override Protected Object Clone ()는 ClonenOntSupportedException {return super.clone (); }} 첫 번째 및 두 번째, 첫 번째, 두 번째. 학생은이 시점에서 동일하지 않습니다. 따라서, 두 번째 학생의 점수를 수정 한 후에는 첫 번째 학생의 점수 값에 영향을 미치지 않아 깊은 복사의 목적을 달성합니다.
그러나 신중하게 생각하면 문제가 발생합니다. 위의 예를 들어 대학 수업과 같은 학생 수업에 참조 유형 속성이있는 경우, 대학 수업이 복제 가능한 인터페이스를 구현 한 다음 학생 수업의 클론 방법에서 대학 클래스 클론 메소드를 호출하도록해야합니다. 나는 그것이 사라 졌다는 것을 알았다. 이 과정은 너무 복잡합니다. 클래스의 모든 관련 참조 유형은 복제 가능한 인터페이스를 구현해야합니다. 나는 그것이 너무 번거로운 느낌이 든다.
딥 카피 문제를 해결하는 가장 좋은 방법은 직렬화를 사용하여 모든 클래스가 복제 가능한 인터페이스를 구현할 필요가 없으며 직접 직접화 및 사형화 할 필요가 없습니다. 봅시다.
import java.io.file; import java.io.fileInputStream; import java.io.fileoutputStream; import java.io.objectinputstream; import java.io.objectoutputStream; java.io.serializable import; 공공 계급 심도 {public static void main (String [] args) {College School = New College ( "Nongda"); 학생 학생 = 신입생 (95, 학교); 복사본 = 새 사본 ( "HZW", 23, Student); 다른 = null; // 사형화 된 클래스 인스턴스를 나타냅니다. // 직렬화 작업을 직렬화하려면 {fileoutputStream fos = new FileOutputStream (새 파일 ( "d : /copy.txt")); ObjectOutputStream OOS = 새로운 ObjectOutputStream (FOS); oos.writeobject (copy); } catch (예외 e) {e.printstacktrace (); } // 사막화 작업을 직렬화 FileInputStream FIS; try {fis = new FileInputStream (새 파일 ( "d : /copy.txt")); ObjectInputStream OIS = New ObjectInputStream (FIS); 다른 = (copy) ois.readobject (); } catch (예외 e) {e.printstacktrace (); } system.out.println (copy == Other); // false system.out.println (copy.student == Other.student); // false system.out.println (copy.student.school == Other.student.school); // false.student.school.schoolname = "wuda"; System.out.println (copy.student.school.schoolname); // nongda}} 클래스 사본 구현 직렬화 가능 {public string name; 공개 int 연령; 공립 학생 학생; 공개 사본 (문자열 이름, int 연령, 학생 학생) {this.name = 이름; this.age = age; this.student = 학생; }} 클래스 학생은 직렬화 가능한 {public int score; 공립 대학 학교; 공개 학생 (Int Score, College School) {this.score = 점수; this.school = 학교; }} Class College는 시리얼이 가능한 {공공 문자열 schoolname; 공립 대학 (String SchoolName) {this.schoolname = SchoolName; }} 출력에서, 사막화 후 생성 된 객체는 원래 오브젝트의 사본이며 동일한 속성 값을 제외하고 원래 객체와 관계가 없음을 알 수 있습니다. 따라서, 우리가 "wuda"에 대한 deserialization 생성 객체의 스쿨 이름을 수정할 때, 우리는 원래 인스턴스의 스쿨 이름을 수정하지 않았으며 여전히 "nongda"를 출력하여 실제 깊은 사본 효과를 달성했습니다. 그러나 직렬화를 달성하기 위해 모든 관련 클래스는 클론 가능한 인터페이스와 클론 방법을 구현하는 것보다 항상 더 편리한 직렬화 가능한 인터페이스를 구현해야합니다.
위의 것은 Java Deep and Shallow Copies에 대한 자세한 설명입니다. 필요한 경우 참조하십시오.