程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java中對象的深復制(深克隆)和淺復制(淺克隆)引見

Java中對象的深復制(深克隆)和淺復制(淺克隆)引見

編輯:關於JAVA

Java中對象的深復制(深克隆)和淺復制(淺克隆)引見。本站提示廣大學習愛好者:(Java中對象的深復制(深克隆)和淺復制(淺克隆)引見)文章只能為提供參考,不一定能成為您想要的結果。以下是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()辦法時,必定要挪用super.clone()呢?在運轉時辰,Object中的clone()辨認出你要復制的是哪個對象,然後為此對象分派空間,並停止對象的復制,將原始對象的內容逐個復制到新對象的存儲空間中。
②繼續自java.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的傳授?代碼改良以下。
改良使先生1的Professor不轉變(深條理的克隆)

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)進程,然則在Java法式師圈子裡又異常抽象地稱為“冷凍”或許“腌鹹菜(picking)”進程;而把對象從流中讀出來的並行化(Deserialization)進程則叫做 “凍結”或許“回鮮(depicking)”進程。
    應該指出的是,寫在流裡的是對象的一個拷貝,而原對象依然存在於JVM外面,是以“腌成鹹菜”的只是對象的一個拷貝,Java鹹菜還可以回鮮。
    在Java說話裡深復制一個對象,經常可以先使對象完成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);
 }
}
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved