Java 딥 카피 및 얕은 카피 분석

본격적으로 주제에 들어가기 전에 다음 딥 카피와 전 카피의 개념을 알아보겠습니다.
얕은 복제본:
새 대상을 만들 것입니다. 이 대상은 원시 대상의 속성 값에 대한 정확한 복사본을 가지고 있습니다. 만약 속성이 기본 유형이라면 복사한 것은 기본 유형의 값입니다.속성이 메모리 주소라면 복사된 것이 메모리 주소이기 때문에 한 대상이 이 주소를 바꾸면 다른 대상에 영향을 미친다.
딥 카피:
대상의 모든 비인용 구성원 변수 값을 복사해야 할 뿐만 아니라 인용 유형의 구성원 변수에 새로운 실례를 만들고 형식 매개 변수 실례 값으로 초기화해야 한다.
개념을 파악한 후 일반적인 객체 할당 작업이 딥 복제본인지 얕은 복제본인지 테스트합니다.
테스트 코드:

public class DepthCopy { 
  public static void main(String[] args) { 
    Copy first = new Copy("hzw", 24); 
    Copy second = first; 
    second.name = "shanxi"; 
    System.out.println(first.name);// shanxi 
  } 
} 
class Copy 
{ 
  public String name; 
  public int age; 
  public Copy(String name,int age) { 
    this.name = name; 
    this.age = age; 
  } 
} 
second에서name 속성 값을shanxi로 수정한 후first의name 속성 값도shanxi로 바뀌었다는 것을 알 수 있다. 이를 통해 일반적인 대상 값이 얕은 복사에 속한다는 것을 알 수 있다.
개체 간의 값이 얕은 복사인지 알게 된 후에 클론이 깊은 복사인지 얕은 복사인지 살펴보겠습니다. 테스트 코드는 위의 Copy 개체가 Cloneable 인터페이스의 clone 방법을 실현하도록 하는 것입니다.

public class DepthCopy { 
  public static void main(String[] args) { 
    Copy first = new Copy("hzw", 24); 
    Copy second = null; 
    try { 
      second = (Copy) first.clone(); 
    } catch (CloneNotSupportedException e) { 
      e.printStackTrace(); 
    } 
    second.name = "shanxi"; 
    System.out.println(first.name);// : hzw 
    System.out.println(first);// : com.hzw.day33.Copy@7f39ebdb 
    System.out.println(second);// : com.hzw.day33.Copy@33abb81e 
  } 
} 
class Copy implements Cloneable 
{ 
  public String name; 
  public int age; 
  public Copy(String name,int age) { 
    this.name = name; 
    this.age = age; 
  } 
  @Override 
  protected Object clone() throws CloneNotSupportedException { 
    return super.clone(); 
  } 
} 
이전에 생성된 대상first와 클론이 생성한 대상second는 두 가지 실례를 볼 수 있기 때문에second에서name 속성의 수정은first에서name 속성에 영향을 주지 않습니다.그러나 우리는 단순히 복제가 딥 카피라고 생각해서는 안 된다. 예를 들어 다음과 같다.

public class DepthCopy { 
  public static void main(String[] args) { 
    Student student = new Student(95); 
    Copy first = new Copy("hzw", 24,student); 
    Copy second = null; 
    try { 
      second = (Copy) first.clone(); 
    } catch (CloneNotSupportedException e) { 
      e.printStackTrace(); 
    } 
    second.name = "shanxi"; 
    second.student.score = 60; 
    System.out.println(first == second);//false 
    System.out.println(first.student == second.student);//true 
    System.out.println(first.student.score);//60 
  } 
} 
class Copy implements Cloneable 
{ 
  public String name; 
  public int age; 
  public Student student; 
  public Copy(String name,int age,Student student) { 
    this.name = name; 
    this.age = age; 
    this.student = student; 
  } 
  @Override 
  protected Object clone() throws CloneNotSupportedException { 
    return super.clone(); 
  } 
} 
class Student  
{ 
  public int score; 
  public Student(int score) { 
    this.score = score; 
  } 
} 
보이시나요?우리는 복제 방식을 통해second를 만들었는데first와second가 두 가지 실례라는 것을 분명히 발견했다. 왜냐하면first==second가 false로 출력되었기 때문이다. 그러나first와second 안의 학생 대상은 같다. second를 통해student의 score 값을 수정한 후에first 안의 학생 score도 바뀌었다. 이것은first와second 안의 학생이 같다는 것이다. 이것은 복제가 얕은 복사라는 것을 설명한다.우리는 복제의 깊은 복사를 실현하려면 Copy 대상의 Student 대상도 Cloneable 인터페이스의 clone 방법을 실현하고 Copy 안의 복제 방법으로 Student의 복제를 되돌려주면 된다. 그러면 Student의 유일한 것을 보장할 수 있다. 수정된 코드는 다음과 같다.

public class DepthCopy { 
  public static void main(String[] args) { 
    Student student = new Student(95); 
    Copy first = new Copy("hzw", 24,student); 
    Copy second = null; 
    try { 
      second = (Copy) first.clone(); 
    } catch (CloneNotSupportedException e) { 
      e.printStackTrace(); 
    } 
    second.name = "shanxi"; 
    second.student.score = 60; 
    System.out.println(first == second);//false 
    System.out.println(first.student == second.student);//false 
    System.out.println(first.student.score);//95 
    System.out.println(second.student.score);//60 
  } 
} 
class Copy implements Cloneable 
{ 
  public String name; 
  public int age; 
  public Student student; 
  public Copy(String name,int age,Student student) { 
    this.name = name; 
    this.age = age; 
    this.student = student; 
  } 
  @Override 
  protected Object clone() throws CloneNotSupportedException { 
    Copy copy = (Copy)super.clone(); 
    copy.student = (Student) student.clone(); 
    return copy; 
  } 
} 
class Student implements Cloneable 
{ 
  public int score; 
  public Student(int score) { 
    this.score = score; 
  } 
  @Override 
  protected Object clone() throws CloneNotSupportedException { 
    return super.clone(); 
  } 
} 
이때first와second와first를 볼 수 있습니다.학생과 second.학생은 모두 같지 않기 때문에second의studentscore를 수정한 후first의studentscore값에 영향을 주지 않고 깊은 복사의 목적을 달성했다.
그러나 곰곰이 생각해 보면 문제가 나온다. 만약에 우리가 상기 예시된 Student 클래스에도 인용 유형의 속성이 존재한다. 예를 들어 College 클래스가 존재한다면 우리는 College 클래스로 하여금 Cloneable 인터페이스를 실현하게 하고 Student 클래스의 Clone 방법에서 College 클래스의clone 방법을 호출하고 Copy 클래스의clone 방법에서 Student 클래스의clone 방법을 호출하는데 이 과정이 매우 복잡하다.클래스의 인용 유형이 모두 Cloneable 인터페이스를 실현하도록 해야 합니다. 귀찮습니다. 그렇습니다. 그렇습니다. 그렇습니다. 다음은 소사람이 등장합니다.
심층 복사 문제를 해결하는 가장 좋은 방법은 바로 서열화 방식을 채택하는 것이다. 이렇게 각종 종류가 모두 Cloneable 인터페이스를 실현하지 않고 직접 서열화 반서열화하면 된다. 우리 한번 봅시다.

import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileOutputStream; 
import java.io.ObjectInputStream; 
import java.io.ObjectOutputStream; 
import java.io.Serializable; 
 
public class DepthCopy { 
  public static void main(String[] args) { 
    College school = new College("nongda"); 
    Student student = new Student(95, school); 
    Copy copy = new Copy("hzw",23, student); 
    Copy another = null;//  
    //  
    try { 
      FileOutputStream fos = new FileOutputStream(new File("d:/copy.txt")); 
      ObjectOutputStream oos = new ObjectOutputStream(fos); 
      oos.writeObject(copy); 
    } catch (Exception e) { 
      e.printStackTrace(); 
    } 
    //  
    FileInputStream fis; 
    try { 
      fis = new FileInputStream(new File("d:/copy.txt")); 
      ObjectInputStream ois = new ObjectInputStream(fis); 
      another = (Copy) ois.readObject(); 
    } catch (Exception e) { 
      e.printStackTrace(); 
    } 
    System.out.println(copy == another);//false 
    System.out.println(copy.student == another.student);//false 
    System.out.println(copy.student.school == another.student.school);//false 
    another.student.school.schoolName = "wuda"; 
    System.out.println(copy.student.school.schoolName);//nongda 
  } 
} 
class Copy implements Serializable 
{ 
  public String name; 
  public int age; 
  public Student student; 
  public Copy(String name,int age,Student student) { 
    this.name = name; 
    this.age = age; 
    this.student = student; 
  } 
} 
class Student implements Serializable 
{ 
  public int score; 
  public College school; 
  public Student(int score,College school) { 
    this.score = score; 
    this.school = school; 
  } 
} 
class College implements Serializable 
{ 
  public String schoolName; 
  public College(String schoolName) { 
    this.schoolName = schoolName; 
  } 
} 
출력에서 알 수 있듯이 반서열화된 후에 생성된 대상은 완전히 원 대상에 대한 복사본이다. 속성 값이 같은 것을 제외하고는 원 대상과 아무런 관계가 없다. 따라서 우리가 반서열화된 생성 대상의 schoolName을'wuda'로 수정할 때 원래의 실례적인 schoolName 값을 수정하지 않았거나'nongda'를 출력했기 때문에 진정한 깊은 복사 효과를 얻었다. 그러나 서열화를 실현하려면모든 관련 클래스는 Serializable 인터페이스를 실현해야 합니다. 이것도 Cloneable 인터페이스를 실현하고 Clone을 실현하는 방법보다 더 편리합니다.
다음은 Java 딥 카피와 얕은 카피에 대한 자세한 설명입니다. 필요한 것은 참고하시기 바랍니다.

좋은 웹페이지 즐겨찾기