자바의 복사 메커니즘을 깊이 이해하다

앞말
모두가 알다시피 자바에서 복사는 깊은 복사와 얕은 복사 두 가지로 나뉜다.자바는 공공 슈퍼 클래스 Object에서 clone이라는 방법을 실현했다. 이런 방법은 clone에서 나온 새로운 대상은 얕은 복사이고 자신이 정의한 clone 방법을 통해 깊은 복사이다.
(1) Object에서 clone 메서드
만약 우리new가 새로운 대상을 낸다면, 하나의 성명으로 인용하고, 그 다음에 다른 성명으로 이전 성명을 인용한다면, 마지막 결과는 이 두 성명의 변수는 같은 대상을 가리키며, 한 곳은 모두 수정될 것이다.만약 우리가 대상의copy를 만들고 싶다면, 이copy는 대상의 각종 속성과 완전히 같고, 이copy를 수정하는 것은 원래의 대상과 아무런 관계가 없다면, 이때 우리는clone 방법을 사용해야 한다.

package Clone;

import java.util.Date;

/**
 * 
 * @author QuinnNorris 
 * java 
 */
public class Clone {

 /**
 * @param args
 * @throws CloneNotSupportedException 
 */
 public static void main(String[] args) throws CloneNotSupportedException {
 // TODO Auto-generated method stub

 ClassA valA = new ClassA(1, "old", new Date());
 //  ClassA , ClassA 
 ClassA valB = valA;
 //  valA valB
 valA.setObject("new");
 //  valA , valB , valA valB 

 valB = valA.clone();// clone 
 }
}
ClassA 클래스의 clone 메서드에 대한 재작성 섹션:

// Cloneable 
public class ClassA implements Cloneable {

 public ClassA clone() throws CloneNotSupportedException {
 return (ClassA) super.clone();// (Object) clone 
 }

}
1. Object에서 clone 방법을 사용하는 방법
어떤 사람이 clone 방법을 사용하는 네 가지 법칙을 총결하여 우리 함께 공유합시다.
  • 대상의 복사본을 얻기 위해 Object 클래스clone() 방법을 사용할 수 있습니다.
  • 파생류에서 기류를 덮어쓰는 clone() 방법은public라고 성명합니다.
  • 파생류clone() 방법에서 호출super.clone()
  • 파생 클래스에서 Cloneable 인터페이스를 구현합니다.
  • 2.protected 수식의clone 방법
    자바에 있어요.lang.Object에서 그는 clone 방법을protected 수식으로 설정했는데 이것은 매우 특수한 상황이다.보호의 역할역은 패키지 가시 + 계승 가능입니다.이렇게 설정하는 이유는 이 방법이 복제된 대상을 되돌려야 하기 때문이다. 즉, 클론 방법이 복제해야 하는 유형은 미지의 것이기 때문에 반환값의 유형을 확정할 방법이 없다. 자연히 자손 후손에게 그것을 다시 쓰게 할 수 밖에 없다. 후손이 계승할 수 있도록 하고 벌리지 않기 위해protected 유형으로 설정한다.
    3. Clone 구현 방법은 Cloneable 인터페이스를 구현해야 한다
    그럼 저희가 clone 방법을 다시 쓸 때 왜 Cloneable 인터페이스를 실현해야 하나요?사실, Cloneable 인터페이스는java의 표기 인터페이스입니다. 표기 인터페이스는 방법과 속성이 없는 인터페이스를 가리키는데 그들이 존재하는 것은 단지 사람들에게 정보를 알리기 위해서입니다. 그리고: xxx instance of Cloneable를 사용할 때 판단할 수 있습니다.Cloneable이라는 인터페이스가 등장한 것은 디자이너가 복제 처리를 해야 한다는 것을 알기 위해서였다.만약 대상이 복제를 필요로 하지만 실현되지 않는다면, (실제로는 여기의 실현을'쓰기'로 바꾸는 것이 더 정확하다) Cloneable 인터페이스는 이미 검증된 이상이 발생할 것이다.
    4. clone 방법을 실현하려면 부류의 clone을 호출해야 한다
    우리는 호출 방법의 이 대상과 똑같은 대상을 복제하는 목적을 달성하기 위해 부류의clone방법을 사용해야 한다. 부류도 이와 같이 유추하여 Object의clone방법에 도달했다는 것을 알게 되면 Object의clone방법은 무슨 소용이 있겠는가?API에서는 다음과 같이 설명합니다.protected Object clone( ) throws CloneNotSupportedException
    이 객체의 복사본을 만들고 반환합니다.
    복제본의 정확한 의미는 객체의 클래스에 의존할 수 있습니다.이렇게 하는 목적은 어떤 대상x에 대해서도
    표현식: x.clone() != x true,
    표현식: x.clone().getClass() == x.getClass() true,
    그러나 반드시 만족해야 할 요구는 아니다.
    일반적인 경우:x.clone().equals(x)true이지만 반드시 만족해야 할 요구는 아니다.
    관례에 따라 되돌아오는 대상은 호출super.clone 을 통해 얻어야 한다.
    클래스와 모든 클래스(Object 제외)가 이 약속을 준수하는 경우x.clone().getClass() == x.getClass() 다음은 API에서 clone에 대한 기본 설명입니다.우리가 결론을 내릴 수 있는 것은 합리적으로 호출되기만 하면 복제된 대상이 되돌아온다는 것이다.실행 시간에 Object의 spuer.clone( ) 는 복제할 대상이 무엇인지 식별한 다음에 이 대상에 공간을 분배하고 대상의 복제를 진행하여 원본 대상의 내용을 일일이 새로운 대상의 저장 공간에 복제합니다.이 클론 객체의 모든 속성은 클론된 객체의 속성과 동일하며 이러한 속성은 두 가지로 나뉩니다.
    첫 번째: 8대 원본 유형 및 변경할 수 없는 객체(예: String)
    두 번째: 기타 클래스 객체
    첫 번째,clone 방법은 그들의 값을 원래의 대상의 값으로 설정합니다. 아무런 문제가 없습니다.두 번째에 대해clone 방법은 복사된 새로운 대상의 인용을 원래 대상의 인용을 가리키는 간단할 뿐, 두 번째 클래스 대상은 두 개의 대상에 의해 수정됩니다.그렇다면 이때는 심천한 카피 개념이 언급된다.
    (2) 얕은 복사본
    얕은 복사: 복사된 대상의 모든 변수는 원래의 대상과 같은 값을 포함하고, 모든 다른 대상에 대한 인용은 여전히 원래의 대상을 가리킨다.얕은 복제는 고려된 대상만 복제할 뿐 인용된 대상은 복제하지 않는다는 얘기다.
    예를 들어 하나의 클래스 A에 다른 클래스 B 유형의 변수가 있다.A에서 clone 함수를 다시 써서 슈퍼를 호출합니다.clone에서 만든 새 대상은 원래 대상의 클래스 B 형식의 변수와 동일합니다. 그들은 같은 B 형식의 변수를 가리킵니다.A에서 B의 변수를 수정하면 새로 복사된 객체에서도 B의 변수가 동일하게 수정됩니다.
    기억해 주십시오. 슈퍼를 직접 호출합니다.clone이 실현하는 clone 방법은 모두 얕은 복사이다.
    (3) 딥 카피
    깊이 복사: 복사된 대상의 모든 변수는 다른 대상을 인용하는 변수를 제외하고 원래의 대상과 같은 값을 포함한다.다른 대상을 인용하는 변수는 복사된 새로운 대상을 가리키며, 더 이상 원래의 인용된 대상이 아니다.다시 말하면 복제할 대상이 인용한 대상을 깊이 복제한 것이다.
    통속적으로 말하면 얕은 복사라고 하면 시작할 때 두 개의 선이 있고 마지막에 다른 종류의 변수가 있다면 이 두 선은 마지막에 하나로 합쳐서 이 변수를 가리키며 모두 그를 조작할 수 있다.깊은 복사는 완전히 완전한 두 줄로 서로 간섭하지 않는다. 왜냐하면 그는 이미 모든 내부 변수의 대상을 모두 복제했기 때문이다.
    코드에 깊이 복사하려면 clone 방법에서 이 클래스의 다른 변수를 호출하는 clone 함수를 많이 써야 합니다.
    (4) 직렬화 딥 카피
    프레임워크에서 때때로 우리는 그 중에서 클론을 다시 쓰는 방법이 없다는 것을 발견한다. 그러면 우리는 대상을 복사해야 할 때 어떻게 조작합니까?답은 우리가 직렬화 방법을 자주 사용하여 Serializable 인터페이스를 실현하는 것이다.
    다른 방법을 찾아 깊은 복사를 대체하는 것도 어쩔 수 없는 일이다. 전통적인 깊은 복사를 사용한다면 한 대상을 복사할 때 그 안에 무수한 층을 쫓아 모든 대상 변수를 복사하는 것이 아니겠는가?이렇게 하는 시간의 소모는 말할 것도 없고, 단지 이런 코드를 쓰는 것만으로도 사람을 두려워하게 할 뿐이다.직렬화 심층 복사는 이런 비교적 간단한 방법이다.
    대상을 흐름에 쓰는 과정은 직렬화(Serilization) 과정이지만 자바 프로그래머들 사이에서는'냉동'또는'절임(picking)'과정이라고 매우 형상적으로 불린다.대상을 흐름에서 읽는 병행화(Deserialization) 과정을'해동'또는'신선도(depicking)'과정이라고 한다.반드시 지적해야 할 것은 흐름에 쓰인 것은 대상의 복사본이고 원래의 대상은 여전히 JVM에 존재하기 때문에'절인 채소'는 대상의 복사본일 뿐이고 자바절인 채소는 신선할 수 있다.
    위에는 인터넷의 전문적인 해석이 있는데, 나도 이곳에서 도끼질을 하지 않을 것이다.자바 언어에서 하나의 대상을 깊이 복제하면 항상 먼저 대상을 Serializable 인터페이스를 실현한 다음에 대상(실제로는 대상의 복사본일 뿐이다)을 하나의 흐름에 쓴 다음에 흐름에서 읽으면 대상을 재건할 수 있다.
    
    public Object deepClone() 
    { 
     //  
     ByteArrayOutoutStream bo=new ByteArrayOutputStream(); 
     ObjectOutputStream oo=new ObjectOutputStream(bo); 
     oo.writeObject(this); 
     // 
     ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray()); 
     ObjectInputStream oi=new ObjectInputStream(bi); 
     return(oi.readObject()); 
    }
    이런 학원파의 코드는 보기에는 매우 복잡해 보이지만, 사실은 대상을 흐름 속에 넣고 다시 꺼낼 뿐이다.무수한 클론을 비교 분석하고 판단하는 것은 그야말로 더할 나위 없이 간단하다.이렇게 하는 전제는 대상과 대상 내부에 인용된 모든 대상이 직렬화되는 것이다. 그렇지 않으면 직렬화되지 않는 대상이transient로 설정되었는지 자세히 살펴야 한다.
    transient: 하나의 대상이 Serilizable 인터페이스를 실현하면 이 대상은 서열화될 수 있다. (서열화는 자바 코드를 바이트 서열의 형식으로 작성하는 것을 가리킨다. 즉, 우리 위의 코드 앞 세 줄의 쓰기 대상이다.) 자바의 이러한 서열화 모델은 개발자에게 많은 편의를 제공하고 구체적인 서열화 과정과 관계를 맺지 않아도 된다. 이 종류가 Serilizable 인터페이스를 실현하기만 하면이 모든 속성과 방법은 자동으로 서열화됩니다.그러나 어떤 경우 어떤 속성은 시퀀스 번호가 필요하지 않기 때문에 이 키워드를 사용한다.Serilizable 인터페이스만 실현하면 서열화되지 않은 속성에 키워드transient를 추가합니다. 서열화된 대상을 추가할 때 이 속성은 지정한 목적지에 서열화되지 않습니다.
    총결산
    실제 응용에서 깊은 복사와 얕은 복사는 두 가지 개념일 뿐이다. 누가 누구보다 좋은지 반드시 실제 업무에 따라 어떻게 대상을 복사하는지 확인해야 한다.만약에 데이터베이스 조작에 있어서 한 장의 시계를 추출할 때 다른 시계와 관련이 없기 위해서는 얕은 복사를 사용해야 한다. 프레임워크의 Serializable에서는 시간이 걸리지만 깊은 복사는 매우 필요하다.
    이상은 바로 이 글의 전체 내용입니다. 본고의 내용이 여러분의 학습이나 업무에 어느 정도 도움이 되고 의문이 있으면 댓글로 교류하시기 바랍니다.

    좋은 웹페이지 즐겨찾기