extended - Java:super.clone() 메서드 및 상속



java copy constructor (4)

B의 clone ()이 A에서 반환하는 clone ()을 반환하고 C의 clone ()이 B의 clone ()이 반환 한 값을 반환하면 C의 clone ()은 A의 clone ()이 반환 한 값을 반환합니다.

https://ffff65535.com

Java에서 clone() 메서드에 관한 질문이 있는데 super.clone() 상속에 사용됩니다 - 여기서 부모 클래스의 clone() 메서드를 단추에서부터 호출합니다.

clone() 메서드는이 객체의 복사본을 반환한다고 가정하지만, 상속의 3 클래스를 heirachy로 호출하고 super.clone() 세 번 호출하면 상속의 최상위 클래스 인 heirachy가 클래스 바로 아래에 있지 않습니다. Object, 그 클래스의 복사본을 얻었습니까?

A, B 및 C의 세 클래스가 있다고 가정합니다. 여기서 A -> B -> C (상속 = ->)

그런 다음 클래스 C에서 super.clone() 을 호출하면 super.clone() 을 호출하는 B에서 clone() 을 호출하고 A에서 clone() 을 호출하여 super.clone() 을 호출합니다. 이번에는 Object.clone ()이 호출됩니다. Object.clone() 에서 반환 된 클래스 A와 관련 this 객체의 복사본이 아닌 이유는 무엇입니까? 그것은 나에게 논리적으로 들린다.


그것의 특별한 고유 한 방법. 이것은 복제를 쉽게하기 위해 수행되었습니다. 그렇지 않으면 조상 클래스의 전체 코드를 복사해야합니다.


직장에서 적어도 두 가지 문제가있는 것 같습니다.

  1. clone ()이 일반적으로 구현되는 방법에 대해 혼란스러워하는 것 같습니다.

  2. 복제가 좋은 아이디어라고 생각하는 것 같습니다. (복사 생성자, 공장 또는 이와 동등한 것을 사용하는 것보다).

다음은 복제 메소드 구현예입니다 .

@Override 
public Object clone() throws CloneNotSupportedException {   
    //get initial bit-by-bit copy, which handles all immutable fields
    Fruit result = (Fruit)super.clone();

    //mutable fields need to be made independent of this object, for reasons
    //similar to those for defensive copies - to prevent unwanted access to
    //this object's internal state
    result.fBestBeforeDate = new Date( this.fBestBeforeDate.getTime() );

    return result;
}

super.clone() 의 결과는 즉시 Fruit 캐스트됩니다. 그러면 상속 메소드가 과일 관련 멤버 데이터 (이 경우 fBestBeforeDate 를 수정할 수 있습니다.

따라서 자식 clone() 메서드를 호출하면 부모 클론을 호출하는 동시에 새로 만든 복사본에 고유 한 수정 사항을 추가합니다. 이 경우 나오는 것은 Fruit 이 아니라 Object 이 될 것입니다.

이제 더 중요한 것은 복제는 나쁜 생각 입니다. 복사 생성자와 팩토리는 훨씬 더 직관적이고 쉽게 유지 관리되는 대안을 제공합니다. 이 예제에 첨부 된 Java Practices 링크의 헤더를 읽으십시오. 여기에는 몇 가지 문제점이 요약되어 있습니다. 조쉬 블로흐 (Josh Bloch)도 훨씬 더 긴 토론을하고 있습니다 . 복제는 반드시 피해야합니다. 복제가 문제라고 생각하는 이유에 대한 훌륭한 요약 단락은 다음과 같습니다.

개체의 복제 방법은 매우 까다 롭습니다. 그것은 필드 사본을 기반으로하고 있으며 "여분의 언어"입니다. 생성자를 호출하지 않고 객체를 만듭니다. 생성자가 설정 한 불변 값을 유지한다는 보장은 없습니다. 썬 내부와 외부 모두 수 많은 버그가있었습니다. 객체를 복제 할 때까지 super.clone을 반복적으로 호출하면 개체의 복사본이 작아집니다. 복제본은 일반적으로 복제중인 개체와 상태를 공유합니다. 해당 상태가 변경 가능하면 두 개의 독립적 인 객체가 없습니다. 하나를 수정하면 다른 하나도 변경됩니다. 그리고 갑자기, 당신은 임의적 인 행동을 취합니다.


한 가지 대답이 받아 들여지더라도, 질문의 첫 부분에 완전히 대답하지는 않는다 (왜 서브 클래스에서의 다운 캐스팅이 항상 효과가 있는지). 비록 내가 그것을 설명 할 수는 없지만, 나는 내 것과 같은 포스터의 혼란을 해결할 수 있다고 생각한다. 우리는 다음과 같은 수업을 진행합니다.

class A implements Cloneable 
{
   @Override
   protected A clone() throws CloneNotSupportedException // could be public
   { 
      Object clone = super.clone();
      System.out.println("Class A: " + clone.getClass()); // will print 'C'
      return (A) clone;
   }
}

class B extends A
{
   @Override
   protected B clone() throws CloneNotSupportedException
   { 
      A clone = super.clone();
      System.out.println("Class B: " + clone.getClass()); // will print 'C'
      return (B) clone;
   }
}

class C extends B
{
   @Override
   protected C clone() throws CloneNotSupportedException
   { 
      B clone = super.clone();
      System.out.println("Class C: " + clone.getClass()); // will print 'C'
      return (C) clone;
   }
}

static main(char[] argv)
{
   C c = new C();
   C cloned_c = c.clone();
}

이 결과는

Class A: C

Class B: C

Class C: C

명령 줄에 인쇄됩니다. 사실, Objectclone() 메소드는 어떻게 든 호출 스택을 내려다 볼 수 있고 체인의 시작 부분에 어떤 유형의 객체 clone() 호출했는지 확인할 수 있습니다. 그러면 호출이 위로 올라가서 Object#clone() 이 실제로 호출되면 해당 유형의 객체가 만들어집니다. 그래서 이것은 클래스 C 에서 이미 이상하게 발생하지만, 왜 다운 캐스트가 ClassCastException 초래하지 않는지 설명 ClassCastException . 나는 OpenJDK를 살펴 보았는데, 이것은 네이티브 코드로 구현 된 자바 블랙 매직에 의해 나타나는 것으로 보인다.





instance