딥 카피(deep copy)와 얕은 카피(shallow copy)는 상대적으로 흔한 개념인데, 특히 C++ 언어에서는 이해하지 못하면 삭제 시 문제가 발생하지만 여기서는 다행히 Java를 사용합니다. Java가 자동으로 객체 재활용을 관리하지만 우리는 여전히 깊은 복사(deep copy)와 얕은 복사(shallow copy)에 충분한 주의를 기울여야 합니다. 왜냐하면 때때로 이 두 개념이 우리에게 많은 혼란을 가져오기 때문입니다.
얕은 복사란 객체를 복사할 때 객체 자체(객체의 기본 변수 포함)만 복사하고 객체에 포함된 참조가 가리키는 객체는 복사하지 않는다는 의미입니다. 전체 복사는 객체 자체를 복사할 뿐만 아니라 객체에 포함된 참조가 가리키는 모든 객체도 복사합니다. 예를 들어, 더 명확하게 설명하면 객체 A1에는 B1에 대한 참조가 포함되고 B1에는 C1에 대한 참조가 포함됩니다. A2를 얻기 위한 얕은 복사본 A1. A2에는 여전히 B1에 대한 참조가 포함되어 있고 B1에는 여전히 C1에 대한 참조가 포함되어 있습니다. 깊은 복사는 A2를 얻기 위한 얕은 복사 A1의 재귀입니다. A2에는 B2(B1의 복사본)에 대한 참조가 포함되고 B2에는 C2(C1의 복사본)에 대한 참조가 포함됩니다.
clone() 메서드를 다시 작성하지 않으면 이 메서드를 호출하여 얻은 객체는 얕은 복사본입니다. 아래에서는 깊은 복사본에 대해 살펴보겠습니다.
얕은 복사본을 살펴보려면 다음 프로그램을 실행하세요.
class Professor0은 Cloneable을 구현합니다. { String name, int age) { this.name = name; this.age = age; } public Object clone() throws CloneNotSupportedException class Student0은 Cloneable { String name; // 상수 객체를 구현합니다. int age; Professor0 p;//학생1과 학생2의 기준값은 동일합니다. Student0(문자열 이름, int age, Professor0 p) { this.name = name; this.p = p; } public Object clone() { o = (Student0) super; .clone(); } catch (CloneNotSupportedException e) { System.out.println(e.toString()) } return o } } public class ShallowCopy; main(String[] args) { Professor0 p = new Professor0("wangwu", 50); Student0 s1 = new Student0("zhangsan", 18, p); Student0 s2 = (Student0) s1.clone(); p.name = "lisi"; s2.p.age = 30; s2.name = "z"; System.out.println("학생 s1의 이름:" + s1.name + "/n 학생 s1의 교수 이름:" + s1.p.name + "," + "/n 학생 s1의 교수 나이" + s1 .p.age);//학생 1의 교수} }
s2는 변경되었지만 s1도 변경되어 s1의 p와 s2의 p가 동일한 개체를 가리킨다는 것을 증명합니다. 실제 요구 사항에는 그렇지 않으므로 전체 복사본이 필요합니다.
class Professor Implement Cloneable { String name; int age; 교수(String name, int age) { this.name = name; this.age = age; } public Object clone() { Object o = super. clone(); } catch (CloneNotSupportedException e) { System.out.println(e.toString()) } return o } } class Student Implements Cloneable { 문자열 이름; int age; Student(문자열 이름, int age, 교수 p) { this.name = age; this.p = p } public Object clone() { 학생 o = null; o = (학생) super.clone(); } catch (CloneNotSupportedException e) { System.out.println(e.toString()) } op = (교수) p.clone(); return o; } } public class DeepCopy { public static void main(String args[]) { long t1 = System.currentTimeMillis(); 교수 p = new Professor("wangwu", 50); = new Student("zhangsan", 18, p); 학생 s2 = (학생) s1.p.name = "lisi"; s2.p.age = 30; System.out.println("name=" + s1.p.name + "," + "age=" + s1.p.age); // 학생 1의 교수는 변경되지 않습니다. long t2 = System.currentTimeMillis(); System.out.println(t2-t1) } }
물론 객체를 직렬화하는 깊은 복사 방법도 있습니다.
import java.io.*; //직렬화는 시간이 많이 걸립니다. class Professor2는 Serialized를 구현합니다. { /** * */ private static final long serialVersionUID = 1L; String name, int age; name = name; this.age = age; } } class Student2는 Serialized { /** * */ private static final long serialVersionUID = 1L; 끊임없는 객체. int age; Professor2 p;//학생1과 학생2의 기준값은 동일합니다. Student2(String name, int age, Professor2 p) { this.name = name; this.p = p; } public Object deepClone() throws IOException, OptionalDataException, ClassNotFoundException { // 스트림 ByteArrayOutputStream bo = new ObjectOutputStream() oo = new ObjectOutputStream(bo); oo.writeObject(this); // 스트림에서 ByteArrayInputStream 읽기 bi = new ByteArrayInputStream(bo.toByteArray()) ObjectInputStream oi = new ObjectInputStream(bi) return (oi.readObject()); /** * @param args */ public static void main(String[] args)는 OptionalDataException을 발생시킵니다. IOException, ClassNotFoundException { long t1 = System.currentTimeMillis(); Professor2 p = new Professor2("wangwu", 50) Student2 s1 = new Student2("zhangsan", 18, p); (); s2.p.name = "lisi"; s2.p.age = 30; System.out.println("name=" + s1.p.name + "," + "age=" + s1.p.age); // 학생 1의 교수는 변경되지 않습니다. long t2 = System.currentTimeMillis(); System.out.println(t2-t1) } }
그러나 직렬화에는 시간이 많이 소요됩니다. 일부 프레임워크에서는 개체를 직렬화한 다음 전송하는 데 시간이 많이 걸리는 경우가 많습니다.