1. 程式人生 > >java實現序列化的作用

java實現序列化的作用

1、序列化是幹什麼的?
  簡單說就是為了儲存在記憶體中的各種物件的狀態(也就是例項變數,不是方法),並且可以把儲存的物件狀態再讀出來。雖然你可以用你自己的各種各樣的方法來儲存object states,但是Java給你提供一種應該比你自己好的儲存物件狀態的機制,那就是序列化。
  2、什麼情況下需要序列化
  a)當你想把的記憶體中的物件狀態儲存到一個檔案中或者資料庫中時候;
  b)當你想用套接字在網路上傳送物件的時候;
  c)當你想通過RMI傳輸物件的時候;
  6、相關注意事項
  a)序列化時,只對物件的狀態進行儲存,而不管物件的方法;
  b)當一個父類實現序列化,子類自動實現序列化,不需要顯式實現Serializable介面;
  c)當一個物件的例項變數引用其他物件,序列化該物件時也把引用物件進行序列化;
  d)並非所有的物件都可以序列化,,至於為什麼不可以,有很多原因了,比如:
  1.安全方面的原因,比如一個物件擁有private,public等field,對於一個要傳輸的物件,比如寫到檔案,或者進行rmi傳輸等等,在序列化進行傳輸的過程中,這個物件的private等域是不受保護的。
  2. 資源分配方面的原因,比如socket,thread類,如果可以序列化,進行傳輸或者儲存,也無法對他們進行重新的資源分配,而且,也是沒有必要這樣實現。
  詳細描述:
  序列化的過程就是物件寫入位元組流和從位元組流中讀取物件。將物件狀態轉換成位元組流之後,可以用java.io包中的各種位元組流類將其儲存到檔案中,管道到另一執行緒中或通過網路連線將物件資料傳送到另一主機。物件序列化功能非常簡單、強大,在RMI、Socket、JMS、EJB都有應用。物件序列化問題在網路程式設計中並不是最激動人心的課題,但卻相當重要,具有許多實用意義。
  一:物件序列化可以實現分散式物件。主要應用例如:RMI要利用物件序列化執行遠端主機上的服務,就像在本地機上執行物件時一樣。
  二:java物件序列化不僅保留一個物件的資料,而且遞迴儲存物件引用的每個物件的資料。可以將整個物件層次寫入位元組流中,可以儲存在檔案中或在網路連線上傳遞。利用物件序列化可以進行物件的“深複製”,即複製物件本身及引用的物件本身。序列化一個物件可能得到整個物件序列。
  從上面的敘述中,我們知道了物件序列化是java程式設計中的必備武器,那麼讓我們從基礎開始,好好學習一下它的機制和用法。
  java序列化比較簡單,通常不需要編寫儲存和恢復物件狀態的定製程式碼。實現java.io.Serializable介面的類物件可以轉換成位元組流或從位元組流恢復,不需要在類中增加任何程式碼。只有極少數情況下才需要定製程式碼儲存或恢復物件狀態。這裡要注意:不是每個類都可序列化,有些類是不能序列化的,例如涉及執行緒的類與特定JVM有非常複雜的關係。
  序列化機制:
  序列化分為兩大部分:序列化和反序列化。序列化是這個過程的第一部分,將資料分解成位元組流,以便儲存在檔案中或在網路上傳輸。反序列化就是開啟位元組流並重構物件。物件序列化不僅要將基本資料型別轉換成位元組表示,有時還要恢復資料。恢復資料要求有恢復資料的物件例項。ObjectOutputStream中的序列化過程與位元組流連線,包括物件型別和版本資訊。反序列化時,JVM用頭資訊生成物件例項,然後將物件位元組流中的資料複製到物件資料成員中。下面我們分兩大部分來闡述:
  處理物件流:
  (序列化過程和反序列化過程)
  java.io包有兩個序列化物件的類。ObjectOutputStream負責將物件寫入位元組流,ObjectInputStream從位元組流重構物件。
  我們先了解ObjectOutputStream類吧。ObjectOutputStream類擴充套件DataOutput介面。
  writeObject()方法是最重要的方法,用於物件序列化。如果物件包含其他物件的引用,則writeObject()方法遞迴序列化這些物件。每個ObjectOutputStream維護序列化的物件引用表,防止傳送同一物件的多個拷貝。(這點很重要)由於writeObject()可以序列化整組交叉引用的物件,因此同一ObjectOutputStream例項可能不小心被請求序列化同一物件。這時,進行反引用序列化,而不是再次寫入物件位元組流。
  下面,讓我們從例子中來了解ObjectOutputStream這個類吧。
  // 序列化 today’s date 到一個檔案中.
  FileOutputStream f = new FileOutputStream(“tmp”);//建立一個包含恢復物件(即物件進行反序列化資訊)的”tmp”資料檔案
  ObjectOutputStream s = new ObjectOutputStream(f);
  s.writeObject(“Today”); //寫入字串物件;
  s.writeObject(new Date()); //寫入瞬態物件;
  s.flush();
  現在,讓我們來了解ObjectInputStream這個類。它與ObjectOutputStream相似。它擴充套件DataInput介面。ObjectInputStream中的方法映象DataInputStream中讀取Java基本資料型別的公開方法。readObject()方法從位元組流中反序列化物件。每次呼叫readObject()方法都返回流中下一個Object。物件位元組流並不傳輸類的位元組碼,而是包括類名及其簽名。readObject()收到物件時,JVM裝入頭中指定的類。如果找不到這個類,則readObject()丟擲ClassNotFoundException,如果需要傳輸物件資料和位元組碼,則可以用RMI框架。ObjectInputStream的其餘方法用於定製反序列化過程。
  例子如下:
  //從檔案中反序列化 string 物件和 date 物件
  FileInputStream in = new FileInputStream(“tmp”);
  ObjectInputStream s = new ObjectInputStream(in);
  String today = (String)s.readObject(); //恢復物件;
  Date date = (Date)s.readObject();
  定製序列化過程:
  序列化通常可以自動完成,但有時可能要對這個過程進行控制。java可以將類宣告為serializable,但仍可手工控制宣告為static或transient的資料成員。
  例子:一個非常簡單的序列化類。
  public class simpleSerializableClass implementsSerializable{
  String sToday=”Today:”;
  transient Date dtToday=new Date();
  }
  序列化時,類的所有資料成員應可序列化除了宣告為transient或static的成員。將變數宣告為transient告訴JVM我們會負責將變元序列化。將資料成員宣告為transient後,序列化過程就無法將其加進物件位元組流中,沒有從transient資料成員傳送的資料。後面資料反序列化時,要重建資料成員(因為它是類定義的一部分),但不包含任何資料,因為這個資料成員不向流中寫入任何資料。記住,物件流不序列化static或transient。我們的類要用writeObject()與readObject()方法以處理這些資料成員。使用writeObject()與readObject()方法時,還要注意按寫入的順序讀取這些資料成員。
  關於如何使用定製序列化的部分程式碼如下:
  //重寫writeObject()方法以便處理transient的成員。
  public void writeObject(ObjectOutputStream outputStream)throws IOException{
  outputStream.defaultWriteObject();//使定製的writeObject()方法可以
  利用自動序列化中內建的邏輯。
  outputStream.writeObject(oSocket.getInetAddress());
  outputStream.writeInt(oSocket.getPort());
  }
  //重寫readObject()方法以便接收transient的成員。
  private void readObject(ObjectInputStream inputStream) throwsIOException,ClassNotFoundException{
  inputStream.defaultReadObject();//defaultReadObject()補充自動序列化
  InetAddressoAddress=(InetAddress)inputStream.readObject();
  int iPort =inputStream.readInt();
  oSocket = new Socket(oAddress,iPort);
  iID=getID();
  dtToday =new Date();
  }
From:

http://www.e800.com.cn/articles/2011/0804/492750.shtml