자바 진급 시리즈 대상 클론

5361 단어
자바 에 있 는 모든 클래스 는 자바 언어 패키지 의 Object 클래스 를 계승 하 는 데 부족 하 다 는 것 을 잘 알 고 있 습 니 다. 원본 코드 를 보 세 요. JDK 디 렉 터 리 에 있 는 src. zip 를 다른 곳 으로 복사 해서 압축 을 풀 수 있 습 니 다. 그 안에 있 는 모든 소스 코드 입 니 다.안에 접근 제한 문자 가 proctected 인 방법 clone () 이 있 음 을 발견 하 였 습 니 다.
protected native Object clone() throws CloneNotSupportedException;

자세히 보면 네 이 티 브 방법 입 니 다. 네 이 티 브 방법 은 자바 언어 가 아 닌 코드 로 자바 프로그램 이 호출 할 수 있다 는 것 을 잘 알 고 있 습 니 다. 자바 프로그램 은 JVM 가상 컴퓨터 에서 실행 되 기 때문에 비교적 밑바닥 에 있 는 운영 체제 와 관련 된 것 을 방문 하려 면 어 쩔 수 없 이 운영 체제 에 가 까 운 언어 로 만 이 루어 질 수 있 습 니 다.
왜 복 제 를 합 니까?
여러분 은 먼저 한 가지 문 제 를 생각 하 세 요. 왜 복제 대상 이 필요 합 니까?그냥 뉴 대상 하면 안 돼 요?정 답 은 복 제 된 대상 은 수 정 된 속성 을 포함 할 수 있 으 며, new 에서 나 온 대상 의 속성 은 모두 초기 화 된 값 이기 때문에 현재 대상 의 '상태' 를 새로운 대상 으로 저장 하려 면 clone 방법 에 의존 합 니 다.그럼 제 가 이 대상 의 임시 속성 을 하나씩 할당 해 주 셔 도 되 지 않 겠 습 니까?그 럴 수 있 습 니 다. 하지만 첫째, 귀 찮 은 것 은 말 하지 않 겠 습 니 다. 둘째, 여러분 은 위의 소스 코드 를 통 해 clone 이 native 방법 이라는 것 을 알 게 되 었 습 니 다. 바로 빠 르 군요. 밑 에서 이 루어 진 것 입 니 다.우리 가 흔히 볼 수 있 는 Object a = new Object () 를 깨 웁 니 다.Object b;b=a;이러한 형식의 코드 는 인용, 즉 대상 이 메모리 에 있 는 주소, a 와 b 대상 이 여전히 같은 대상 을 가리 키 고 있 습 니 다.clone 방법 을 통 해 값 을 부여 하 는 대상 은 원래 의 대상 과 동시에 독립 적 으로 존재 합 니 다.이렇게 쓸데없는 말 을 많이 하 더 니 드디어 본론 으로 들 어 갔다.
어떻게 복 제 를 실현 합 니까?
믿 기지 않 을 정도 로 간단 해.클래스 뒤에 implements Cloneable 을 직접 설명 합 니 다.이 인터페이스 에 대한 원본 코드 는 다음 과 같 습 니 다.
public interface Cloneable {
}

그것 은 빈 인터페이스 로 표시 하 는 역할 을 하 는 것 을 볼 수 있다.Cloneable 인터페이스 가 구현 되 지 않 으 면 clone 방법 을 직접 사용 합 니 다. 프로그램 은 Clone NotSupported Exception 이상 을 던 집 니 다.그리고 클 라 이언 트 방법 을 다시 쓰 고 Public 접근 단계 로 수정 합 니 다.전형 적 인 밤 을 들 어 라.
class Outer implements Cloneable {
    public int name;
    public Inner inner;
      
    @Override
    public Object clone() throws CloneNotSupportedException {
      return super.clone();
    }
public static void main(String[] args){
    Outer o_one = new Outer();
    o_one.inner = new Inner("zhangsan");
    try {
    Object obj = o_one.clone();
    Outer o_two = (Outer)obj;
    System.out.println(o_one==o_two);    //  false
    System.out.println(o_one.inner.name.equals(o_two.inner.name)); //  true
    } catch (CloneNotSupportedException e) {
     e.printStackTrace();
    }
}
}

위의 코드 가 실 현 된 것 은 사실 얕 은 복제 이다. 얕 은 복 제 는 인용 유형 에 대해 서 만 복사 하고 인용 하 며 두 대상 을 진정 으로 독립 시 키 지 않 고 서로 관계 가 없다.얕 은 클론 이기 때문에 imp 2 는 child 의 특정한 속성 을 수정 한 후에 imp 1 에서 child 의 속성 도 달라 집 니 다.또는 두 대상 의 주 소 를 비교 합 니 다: imp1. child = imp2. child, 돌아 온 결 과 는 true 입 니 다.단, 대상 이 원본 데이터 필드 나 가 변 대상 필드 (예 를 들 어 String 형식) 만 포함 하고 있다 면 얕 은 복 제 를 추천 합 니 다.
심 클론
클래스 의 모든 인용 형식 을 수정 하여 Cloneable 인터페이스 도 실현 하도록 합 니 다.그리고 이 클래스 의 clone 방법 을 수정 합 니 다.
public class Inner implements  Cloneable{

  public String name;

  public Child(String name) {
      this.name = name;
  }

  @Override
  public String toString() {
      return "Inner name  :" + name;
  }

  @Override
  protected Object clone() throws CloneNotSupportedException {
      return super.clone();
  }
}

이 종류의 clone 방법 을 수정 합 니 다:
static class Outer implements Cloneable {
  public int count;
  public Inner inner;
      
      
  @Override
  public Object clone() throws CloneNotSupportedException {
      Outer obj = (Outer)super.clone();
      obj.inner = (Inner) inner.clone();
      return obj;
  }
}

요점 을 그 렸 다.
  • clone 방법 을 다시 써 야 합 니 다. 부모 클래스 만 호출 하 는 방법 이 아니 라 속성 을 호출 하 는 clone 방법 도 필요 합 니 다.
  • 대상 간 100% 데이터 분리
  • 대상 에 인용 유형의 속성 이 존재 한다 면 딥 클론
  • 을 사용 하 는 것 을 권장 합 니 다.
  • 심 한 복 제 는 얕 은 복제 보다 시간 이 더 걸 리 고 효율 이 낮다
  • 다 층 복제 문제 해결
    인용 유형 에 인용 유형 이 많이 포함 되 어 있 거나 내부 인용 유형의 클래스 에 인용 유형 이 포함 되 어 있 으 면 clone 방법 을 사용 하 는 것 이 번 거 로 울 수 있 습 니 다.이때 우 리 는 대상 의 심 복 제 를 직렬 화 하 는 방식 으로 실현 할 수 있다.
    public class Outer implements Serializable{
      private static final long serialVersionUID = 369285298572941L;  //       ID
      public Inner inner;
      
      public Outer myclone() {
          Outer outer = null;
          try {
              ByteArrayOutputStream baos = new ByteArrayOutputStream();
              ObjectOutputStream oos = new ObjectOutputStream(baos);
              oos.writeObject(this);
      
              ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
              ObjectInputStream ois = new ObjectInputStream(bais);
              outer = (Outer) ois.readObject();
          } catch (IOException e) {
              e.printStackTrace();
          } catch (ClassNotFoundException e) {
              e.printStackTrace();
          }
          return outer;
      }
    }
    

    Inner 도 Serializable 을 실현 해 야 합 니 다. 그렇지 않 으 면 직렬 화 할 수 없습니다.
    public class Inner implements Serializable{
      private static final long serialVersionUID = 872390113109L; //       ID
      public String name = "";
    
      public Inner(String name) {
          this.name = name;
      }
    
      @Override
      public String toString() {
          return "Inner name  :" + name;
      }
    }
    
    

    이렇게 하면 두 대상 이 메모리 공간 에서 완전히 독립 적 으로 존재 하고 상대방 의 값 에 영향 을 주지 않 게 할 수 있다.
    Tips
  • 복제 방법 에서 만약 에 우리 가 가 변 대상 의 final 도 메 인 을 복사 해 야 한다 면 final 의 제한 으로 인해 실제 적 으로 컴 파일 하여 통과 할 수 없다.따라서 복 제 를 실현 하기 위해 서 는 이 가 변 대상 역 의 final 키 워드 를 버 리 는 것 을 고려 해 야 한다.
  • 스 레 드 안전 류 로 Cloneable 인 터 페 이 스 를 실현 하기 로 결정 하면 clone 방법 으로 동기 화 작업 을 해 야 합 니 다.기본 Object. clone 방법 은 동기 화 되 지 않 았 습 니 다.
  • 좋은 웹페이지 즐겨찾기