자바 의 깊 은 복사 와 얕 은 복사 소개

10481 단어 딥 카피
머리말   대상 복사(Object Copy)는 한 대상 의 속성 을 같은 유형의 대상 에 복사 하 는 것 이다.프로그램 에서 복사 대상 은 흔히 볼 수 있 는데 주로 새로운 문맥 환경 에서 대상 의 부분 이나 모든 데 이 터 를 재 활용 하기 위해 서 입 니 다.자바 에는 세 가지 유형의 대상 복사:얕 은 복사(Shallow Copy),깊 은 복사(Deep Copy),지연 복사(Lazy Copy)가 있 습 니 다.
2.얕 은 복사 1.얕 은 복사 가 무엇 입 니까?   얕 은 복사 본 은 위치 에 따라 복사 대상 으로 새로운 대상 을 만 들 것 입 니 다.이 대상 은 원시 대상 속성 값 의 정확 한 복사 본 을 가지 고 있 습 니 다.속성 이 기본 유형 이 라면 기본 유형의 값 을 복사 합 니 다.속성 이 메모리 주소(참조 형식)라면 메모리 주 소 를 복사 합 니 다.따라서 한 대상 이 이 주 소 를 바 꾸 면 다른 대상 에 게 영향 을 줄 수 있 습 니 다.

  그림 에서 SourceObject 는 int 형식의 속성 인'field 1'과 인용 유형 속성 인'refObj'(Contained Object 형식의 대상 참조)가 있 습 니 다.SourceObject 를 얕 게 복사 할 때 CopiedObject 를 만 들 었 습 니 다."field 1"복사 값 을 포함 하 는 속성 인"field 2"와 refObj 자 체 를 가리 키 는 참조 가 있 습 니 다."field 1"은 기본 형식 이기 때문에 값 을"field 2"에 복사 할 뿐"refObj"는 참조 형식 이기 때문에 CopiedObject 는"refObj"와 같은 주 소 를 가리 키 고 있 습 니 다.따라서 SourceObject 의'refObj'에 대한 어떠한 변화 도 CopiedObject 에 영향 을 줄 수 있다.
2.얕 은 복사 어떻게 실현
다음은 얕 은 복사 본 을 실현 하 는 예 이다

public class Subject {
    private String name;
   public Subject(String s) {
      name = s;
   }
   public String getName() {
      return name;
   }
   public void setName(String s) {
      name = s;
   }
}
public class Student implements Cloneable {
    //
   private Subject subj;

   private String name;

   public Student(String s, String sub) {
      name = s;
      subj = new Subject(sub);
   }

   public Subject getSubj() {
      return subj;
   }

   public String getName() {
      return name;
   }

   public void setName(String s) {
      name = s;
   }

   /**
    *  clone()
    * @return
    */
   public Object clone() {
      //
      try {
         // clone()
         return super.clone();
      } catch (CloneNotSupportedException e) {
         return null;
      }
   }
}
public class CopyTest {
    public static void main(String[] args) {
        //
        Student stud = new Student("John", "Algebra");
        System.out.println("Original Object: " + stud.getName() + " - " + stud.getSubj().getName());
        //
        Student clonedStud = (Student) stud.clone();
        System.out.println("Cloned Object: " + clonedStud.getName() + " - " + clonedStud.getSubj().getName());
        // :
        System.out.println("Is Original Object the same with Cloned Object: " + (stud == clonedStud));
        // name
        System.out.println("Is Original Object's field name the same with Cloned Object: " +
     (stud.getName() == clonedStud.getName()));
        // subj
        System.out.println("Is Original Object's field subj the same with Cloned Object: " +
    (stud.getSubj() == clonedStud.getSubj()));
        stud.setName("Dan");
        stud.getSubj().setName("Physics");
        System.out.println("Original Object after it is updated: " + stud.getName() + " - " +
     stud.getSubj().getName());
        System.out.println("Cloned Object after updating original object: " + clonedStud.getName() +
     " - " + clonedStud.getSubj().getName());
    }
}
출력 결 과 는 다음 과 같 습 니 다. Original Object: John - Algebra Cloned Object: John - Algebra Is Original Object the same with Cloned Object: false Is Original Object's field name the same with Cloned Object: true Is Original Object's field subj the same with Cloned Object: true Original Object after it is updated: Dan - Physics Cloned Object after updating original object: John - Physics     이 예 에서 복사 할 클래스 Student 에 게 Clonable 인터페이스 와 Object 류 의 clone()방법 을 다시 쓰 라 고 한 다음 에 방법 내부 에서 슈퍼 clone()방법 을 호출 합 니 다.출력 결과 에서 볼 수 있 듯 이 원본 대상 stud 의"name"속성 에 대한 변 화 는 복사 대상 clonedStud 에 영향 을 주지 않 지만 인용 대상 subj 의"name"속성 에 대한 변 화 는 복사 대상 clonedStud 에 영향 을 미친다.
3.딥 카피 1.딥 카피 가 무엇 입 니까?   깊이 복사 하면 모든 속성 을 복사 하고 속성 이 가리 키 는 동적 분 배 된 메모 리 를 복사 합 니 다.대상 이 인용 한 대상 과 함께 복사 할 때 깊 은 복사 가 발생 합 니 다.깊 은 복사 보 다 는 얕 은 복사 속도 가 느 리 고 비용 이 많이 든다
위의 그림 에서 SourceObject 는 int 형식의 속성 인'field 1'과 인용 유형 속성 인'refObj 1'(Contained Object 형식의 대상 참조)이 있 습 니 다.SourceObject 를 깊이 복사 할 때 CopiedObject 를 만 들 었 습 니 다."field 1"복사 값 을 포함 하 는 속성"field 2"와"refObj 1"복사 값 을 포함 하 는 참조 형식 속성"refObj 2"가 있 습 니 다.따라서 SourceObject 의"refObj"에 대한 어떠한 변화 도 CopiedObject 에 영향 을 주지 않 습 니 다.
2.딥 복사 어떻게 실현   다음은 심 복 사 를 실현 하 는 예 이다.다만 얕 은 복사 예 에서 약간의 변경 을 했 을 뿐 Subject 와 Copytest 류 는 변 하지 않 았 다

public class Student implements Cloneable {
   //
   private Subject subj;

   private String name;

   public Student(String s, String sub) {
      name = s;
      subj = new Subject(sub);
   }

   public Subject getSubj() {
      return subj;
   }

   public String getName() {
      return name;
   }

   public void setName(String s) {
      name = s;
   }

   /**
    * clone()
    *
    * @return
    */
   public Object clone() {
      // , ,
      Student s = new Student(name, subj.getName());
      return s;
   }
}
출력 결 과 는 다음 과 같 습 니 다.  Original Object: John - Algebra Cloned Object: John - Algebra Is Original Object the same with Cloned Object: false Is Original Object's field name the same with Cloned Object: true Is Original Object's field subj the same with Cloned Object: false Original Object after it is updated: Dan - Physics Cloned Object after updating original object: John - Algebra  clone()방법의 약간의 변 화 를 쉽게 발견 할 수 있다.깊 은 복사 이기 때문에 복사 류 의 대상 을 만들어 야 합 니 다.Student 클래스 에 대상 인용 이 있 기 때문에 Student 클래스 에서 Cloneable 인 터 페 이 스 를 실현 하고 clone 방법 을 다시 써 야 합 니 다.
3.직렬 화 를 통 해 심 한 복사 실현    직렬 화 를 통 해 딥 복사 도 가능 하 다.서열 화 는 무엇 을 하 는 것 입 니까?전체 대상 그림 을 영구적 인 저장 파일 에 기록 하고 필요 할 때 읽 어 오 는 것 은 읽 어야 할 때 전체 대상 그림 의 복사 가 필요 하 다 는 것 을 의미한다.이것 이 바로 당신 이 상 대 를 깊이 복사 할 때 진정 으로 필요 한 것 입 니 다.직렬 화 를 통 해 깊이 복사 할 때 대상 그림 의 모든 종 류 를 직렬 화 할 수 있 도록 확보 해 야 합 니 다

public class ColoredCircle implements Serializable {
   private int x;
   private int y;

   public ColoredCircle(int x, int y) {
      this.x = x;
      this.y = y;
   }

   public int getX() {
      return x;
   }

   public void setX(int x) {
      this.x = x;
   }

   public int getY() {
      return y;
   }

   public void setY(int y) {
      this.y = y;
   }

   @Override
   public String toString() {
      return "x=" + x + ", y=" + y;
   }
}
public class DeepCopy {

   public static void main(String[] args) throws IOException {
      ObjectOutputStream oos = null;
      ObjectInputStream ois = null;

      try {
         //
         ColoredCircle c1 = new ColoredCircle(100, 100);
         System.out.println("Original = " + c1);

         ColoredCircle c2 = null;

         //
         ByteArrayOutputStream bos = new ByteArrayOutputStream();
         oos = new ObjectOutputStream(bos);
         //
         oos.writeObject(c1);
         oos.flush();
         ByteArrayInputStream bin = new ByteArrayInputStream(bos.toByteArray());
         ois = new ObjectInputStream(bin);
         //
         c2 = (ColoredCircle) ois.readObject();

         //
         System.out.println("Copied   = " + c2);
         //
         c1.setX(200);
         c1.setY(200);
         //
         System.out.println("Original = " + c1);
         System.out.println("Copied   = " + c2);
      } catch (Exception e) {
         System.out.println("Exception in main = " + e);
      } finally {
         oos.close();
         ois.close();
      }
   }
}
출력 결 과 는 다음 과 같 습 니 다. Original = x=100, y=100  Copied = x=100, y=100  Original = x=200, y=200  Copied=x=100,y=100 여기 서 다음 과 같은 몇 가지 일 을 해 야 합 니 다.(1)대상 그림 의 모든 클래스 가 직렬 화 되 어 있 는 지 확인 하 십시오.(2)입 출력 흐름 을 만 듭 니 다.(3)이 입 출력 흐름 을 사용 하여 대상 의 입력 과 대상 출력 흐름 을 만 듭 니 다.(4)복사 하고 싶 은 대상 을 대상 의 출력 흐름 에 전달 합 니 다.(5)대상 의 입력 흐름 에서 새로운 대상 을 읽 고 보 낸 대상 의 클래스 로 전환 합 니 다.    이 예 에서,나 는 ColoredCircle 대상 c1 을 만 들 고 그것 을 직렬 화(ByteArray OutputStream 에 기록)했다.그리고 나 서 나 는 이 직렬 화 된 대상 을 반 직렬 화하 고 c2 에 저장 했다.그리고 나 서 나 는 원본 대상 c1 을 수정 했다.그리고 결 과 는 보시 다시 피 c1 은 c2 와 다 르 며 c1 에 대한 어떠한 수정 도 c2 에 영향 을 주지 않 습 니 다.
이러한 방식 은 그 자체 의 제한 과 문제 가 있 습 니 다.transient 변 수 를 직렬 화 할 수 없 기 때문에 이 방법 을 사용 하면 transient 변 수 를 복사 할 수 없습니다.
   성능 문제 다.socket 을 만 들 고 대상 을 직렬 화 하 며 socket 을 통 해 전송 한 다음 반 직렬 화 합 니 다.이 과정 은 기 존 대상 을 호출 하 는 방법 에 비해 느 립 니 다.그래서 성능 에 있어 서 는 천양지차 가 있 을 수 있 습 니 다.만약 성능 이 당신 의 코드 에 있어 서 매우 중요 하 다 면,이런 방식 을 사용 하지 않 는 것 을 권장 합 니 다.그것 은 Clonable 인 터 페 이 스 를 실현 하 는 방식 으로 깊이 복사 하 는 것 보다 거의 100 배 나 많은 시간 이 걸린다.
4.복사 지연   복사 지연 은 얕 은 복사 와 깊 은 복사 의 조합 으로 실제로 거의 사용 되 지 않 는 다.처음에 대상 을 복사 할 때 속도 가 빠 른 얕 은 복사 본 을 사용 하고 얼마나 많은 대상 이 이 데 이 터 를 공유 하 는 지 계수 기 를 사용 합 니 다.프로그램 이 원본 대상 을 수정 하려 고 할 때 데이터 가 공유 되 는 지 여 부 를 결정 하고 필요 에 따라 깊이 복사 합 니 다.   복사 지연 은 밖에서 보면 깊 은 복사 로 보이 지만 가능 하 다 면 얕 은 복사 속 도 를 이용 할 것 이다.원본 대상 의 인용 이 자주 바 뀌 지 않 을 때 지연 복 사 를 사용 할 수 있 습 니 다.계수기 가 존재 하기 때문에 효율 은 매우 높 지만,단지 상수 급 의 지출 일 뿐이다.그리고 어떤 경우 에는 순환 인용 이 문제 가 될 수 있다.
5.어떻게 선택 합 니까?  대상 의 속성 이 모두 기본 유형 이 라면 얕 은 복사 본 을 사용 할 수 있 지만 대상 이 인용 속성 이 있다 면 구체 적 인 수 요 를 바탕 으로 얕 은 복사 인지 깊 은 복사 인지 선택해 야 한다.내 말 은 대상 의 인용 이 언제든지 바 뀌 지 않 는 다 면 깊 은 복사 본 을 사용 할 필요 가 없고 얕 은 복사 만 사용 하면 된다 는 것 이다.대상 인용 이 자주 바 뀌 면 심 한 복사 본 을 사용 해 야 한다.변 함 없 는 규칙 은 없다.모든 것 은 구체 적 인 수요 에 달 려 있다.

좋은 웹페이지 즐겨찾기