Java의 객체에 대한 딥 클론 및 얕은 클론 소개

1. 얕은 복제와 깊은 복제 개념
Υ연한 복제(연한 복제)
복사된 대상의 모든 변수는 원래의 대상과 같은 값을 포함하고, 모든 다른 대상에 대한 인용은 여전히 원래의 대상을 가리킨다.얕은 복제는 고려된 대상만 복제할 뿐 인용된 대상은 복제하지 않는다는 얘기다.
⑵ 딥 복제(딥 복제)
복사된 대상의 모든 변수는 다른 대상을 인용하는 변수를 제외하고 원래의 대상과 같은 값을 포함한다.다른 대상을 인용하는 변수는 복사된 새로운 대상을 가리키며, 더 이상 원래의 인용된 대상이 아니다.다시 말하면 복제할 대상이 인용한 대상을 깊이 복제한 것이다.
2. Java의 clone () 메서드
Υclone 방법으로 객체를 복사하여 호출자에게 반환합니다.일반적으로 clone () 메서드는 다음과 같습니다.
① 모든 대상x에 x.clone ()!=x//클론 객체가 원래 객체와 동일하지 않음
② 모든 객체 x에는 x.clone()이 있습니다.getClass () = x.getClass ()//클론 객체는 원래 객체 유형과 동일합니다.
③ 객체 x의 equals () 방법이 적절하게 정의된 경우 x.clone ().equals(x)는 성립되어야 한다.
⑵ Java의 객체 클론
① 객체의 복사본을 얻기 위해 Object 클래스의 clone () 방법을 사용할 수 있습니다.
② 파생 클래스에서 기본 클래스를 덮어쓰는 clone () 방법은public라고 합니다.
③ 파생 클래스의 clone () 방법에서 super를 호출합니다.clone().
④ 파생 클래스에서 Cloneable 인터페이스를 구현합니다.
다음 코드를 참조하십시오.

public class Student implements Cloneable 
{ 
  String name; 
 int age; 
  Student(String name,int age) 
  { 
  this.name=name; 
  this.age=age; 
  } 
 public Object clone() 
  { 
   Object o=null; 
  try 
   { 
   o=(Student)super.clone();//Object  clone() 。 
   } 
  catch(CloneNotSupportedException e) 
   { 
    System.out.println(e.toString()); 
   } 
  return o; 
  }  
 
 public static void main(String[] args) 
  { 
  Student s1=new Student("zhangsan",18); 
  Student s2=(Student)s1.clone(); 
  s2.name="lisi"; 
  s2.age=20; 
  // 2 , 1 。
  System.out.println("name="+s1.name+","+"age="+s1.age); 
  System.out.println("name="+s2.name+","+"age="+s2.age);
 }
} 
설명:
① 왜 우리가 파생 클래스에서 Object의 clone () 방법을 덮어쓸 때 반드시 슈퍼를 호출해야 하는가.클론()은요?실행 시간에, Object의 clone () 은 복사할 대상이 무엇인지 식별하고, 이 대상에 공간을 분배하고, 대상의 복사를 진행하며, 원본 대상의 내용을 일일이 새로운 대상의 저장 공간에 복사합니다.
② 자바에서 상속한다.lang.Object 클래스의clone () 방법은 얕은 복사입니다.다음 코드는 이를 증명할 수 있다.

class Professor 
{ 
  String name; 
  int age; 
  Professor(String name,int age) 
  { 
  this.name=name; 
  this.age=age; 
  } 
} 
public class Student implements Cloneable 
{ 
  String name;//  。 
  int age; 
  Professor p;//  1 2 。 
  Student(String name,int age,Professor p) 
  { 
  this.name=name; 
  this.age=age; 
  this.p=p; 
  } 
 public Object clone() 
  { 
   Student o=null; 
  try 
   { 
    o=(Student)super.clone(); 
   } 
  catch(CloneNotSupportedException e) 
   { 
    System.out.println(e.toString()); 
   } 
   o.p=(Professor)p.clone(); 
  return o; 
  }  
 public static void main(String[] args) 
 { 
  Professor p=new Professor("wangwu",50); 
  Student s1=new Student("zhangsan",18,p); 
  Student s2=(Student)s1.clone(); 
  s2.p.name="lisi"; 
  s2.p.age=30;  
  System.out.println("name="+s1.p.name+","+"age="+s1.p.age);
  System.out.println("name="+s2.p.name+","+"age="+s2.p.age);
  // 1 2 lisi,age 30。
  } 
} 
그러면 어떻게 심층적인 복제, 즉 s2를 수정한 교수가 s1의 교수에게 영향을 주지 않도록 실현해야 합니까?코드 개선은 다음과 같습니다.
향상된 Professor 1 변경 사항 없음(심층 복제)

class Professor implements Cloneable 
{ 
  String name; 
  int age; 
  Professor(String name,int age) 
  { 
  this.name=name; 
  this.age=age; 
  } 
 public Object clone() 
  { 
   Object o=null; 
  try 
   { 
    o=super.clone(); 
   } 
  catch(CloneNotSupportedException e) 
   { 
    System.out.println(e.toString()); 
   } 
  return o; 
  } 
} 
public class Student implements Cloneable 
{ 
  String name; 
  int age; 
  Professor p; 
  Student(String name,int age,Professor p) 
  { 
  this.name=name; 
  this.age=age; 
  this.p=p; 
  } 
 public Object clone() 
  { 
   Student o=null; 
  try 
   { 
    o=(Student)super.clone(); 
   } 
  catch(CloneNotSupportedException e) 
   { 
    System.out.println(e.toString()); 
   } 
   // 
   o.p=(Professor)p.clone(); 
  return o; 
  }  
 public static void main(String[] args) 
  { 
  Professor p=new Professor("wangwu",50); 
  Student s1=new Student("zhangsan",18,p); 
  Student s2=(Student)s1.clone(); 
  s2.p.name="lisi"; 
  s2.p.age=30; 
  // 1   。
  System.out.println("name="+s1.p.name+","+"age="+s1.p.age); 
  System.out.println("name="+s2.p.name+","+"age="+s2.p.age); 
 } 
} 
3. 직렬화를 이용하여 심층 복제를 한다(주로 비교적 복잡한 대상의 심층 복제를 다시 쓰는 clone () 방법을 피하기 위해 프로그램이 단점 리셋 등 기능을 실현할 수 있다)
대상을 흐름에 쓰는 과정은 직렬화(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로 설정될 수 있는지 자세히 고찰하여 복제 과정에서 제외해야 한다.상례 코드의 개선은 다음과 같다.

class Teacher implements Serializable{
  String name;
  int age;
  public void Teacher(String name,int age){
  this.name=name;
  this.age=age;
  }
}
public class Student implements Serializable{
 String name;// 
 int age;
 Teacher t;// 1 2 。
 public void Student(String name,int age,Teacher t){
  this.name=name;
  this.age=age;
  this.p=p;
 }
 public Object deepClone() throws IOException,
    OptionalDataException,ClassNotFoundException{// 
  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());
 }
 public static void main(String[] args){ 
  Teacher t=new Teacher("tangliang",30);
  Student s1=new Student("zhangsan",18,t);
  Student s2=(Student)s1.deepClone();
  s2.t.name="tony";
  s2.t.age=40;
  // 1 
  System.out.println("name="+s1.t.name+","+"age="+s1.t.age);
 }
}

좋은 웹페이지 즐겨찾기