物件的序列化(Serialization)

逸卿發表於2014-10-24

from:http://www.cnblogs.com/vicenteforever/articles/1471775.html


一、序列化的概念和目的 

1.什麼是序列化 

            物件的壽命通常隨著生成該物件的程式的終止而終止。有時候,可能需要將物件的狀態儲存下來,在需要時再將物件恢復。我們把物件的這種能記錄自己的狀態以便將來再生的能力。叫作物件的持續性(persistence)。物件通過寫出描述自己狀態的數值來記錄自己 ,這個過程叫物件的序列化(Serialization) 。序列化的主要任務是寫出物件例項變數的數值。如果交量是另一物件的引用,則引用的物件也要序列化。這個過程是遞迴的,序列化可能要涉及一個複雜樹結構的單行化,包括原有物件、物件的物件、物件的物件的物件等等。物件所有權的層次結構稱為圖表(graph)。 

2.序列化的目的 

            Java物件的單行化的目標是為Java的執行環境提供一組特性,如下所示: 

1)       儘量保持物件序列化的簡單扼要 ,但要提供一種途徑使其可根據開發者的要求進行擴充套件或定製。 

2)       序列化機制應嚴格遵守Java的物件模型 。物件的序列化狀態中應該存有所有的關於種類的安全特性的資訊。 

3)       物件的序列化機制應支援Java的物件持續性。 

4)       物件的序列化機制應有足夠的 可擴充套件能力以支援物件的遠端方法呼叫(RMI)。 

5)       物件序列化應允許物件定義自身 的格式即其自身的資料流表示形式,可外部化介面來完成這項功能。

 

 

 

二、序列化方法 
            從JDK1.1開始,Java語言提供了物件序列化機制 ,在java.io包中,介面Serialization用來作為實現物件序列化的工具 ,只有實現了Serialization的類的物件才可以被序列化。 

            Serializable介面中沒有任何的方法。當一個類宣告要實現Serializable介面時,只是表明該類參加序列化協議,而不需要實現任何特殊的方法。下面我們通過例項介紹如何對物件進行序列化。 

1.定義一個可序列化物件 

            一個類,如果要使其物件可以被序列化,必須實現Serializable介面。我們定義一個類Student如下:

  1. import java.io.Serializable;   
  2.   
  3. public class Student implements Serializable {   
  4.   
  5.     int id;// 學號   
  6.   
  7.     String name;// 姓名   
  8.   
  9.     int age;// 年齡   
  10.   
  11.     String department; // 系別   
  12.   
  13.     public Student(int id, String name, int age, String department) {   
  14.   
  15.         this.id = id;   
  16.   
  17.         this.name = name;   
  18.   
  19.         this.age = age;   
  20.   
  21.         this.department = department;   
  22.   
  23.     }   
  24.   
  25. }  

2.構造物件的輸入/輸出流 

            要序列化一個物件,必須與一定的物件輸出/輸入流聯絡起來,通過物件輸出流將物件狀態儲存下來,再通過物件輸入流將物件狀態恢復。 

            java.io包中,提供了ObjectInputStream和ObjectOutputStream將資料流功能擴充套件至可讀寫物件 。在ObjectInputStream 中用readObject()方法可以直接讀取一個物件,ObjectOutputStream中用writeObject()方法可以直接將物件儲存到輸出流中。

  1. import java.io.FileInputStream;   
  2. import java.io.FileOutputStream;   
  3. import java.io.IOException;   
  4. import java.io.ObjectInputStream;   
  5. import java.io.ObjectOutputStream;   
  6.   
  7. public class ObjectSer {   
  8.   
  9.     public static void main(String args[]) throws IOException,   
  10.             ClassNotFoundException {   
  11.   
  12.         Student stu = new Student(981036"LiuMing"18"CSD");   
  13.   
  14.         FileOutputStream fo = new FileOutputStream("data.ser");   
  15.   
  16.         ObjectOutputStream so = new ObjectOutputStream(fo);   
  17.   
  18.         try {   
  19.   
  20.             so.writeObject(stu);   
  21.   
  22.             so.close();   
  23.   
  24.         } catch (IOException e) {   
  25.             System.out.println(e);   
  26.         }   
  27.   
  28.         stu = null;   
  29.   
  30.         FileInputStream fi = new FileInputStream("data.ser");   
  31.   
  32.         ObjectInputStream si = new ObjectInputStream(fi);   
  33.   
  34.         try {   
  35.   
  36.             stu = (Student) si.readObject();   
  37.   
  38.             si.close();   
  39.   
  40.         } catch (IOException e)   
  41.   
  42.         {   
  43.             System.out.println(e);   
  44.         }   
  45.   
  46.         System.out.println("Student Info:");   
  47.   
  48.         System.out.println("ID:" + stu.id);   
  49.   
  50.         System.out.println("Name:" + stu.name);   
  51.   
  52.         System.out.println("Age:" + stu.age);   
  53.   
  54.         System.out.println("Dep:" + stu.department);   
  55.   
  56.     }   
  57.   
  58. }  

執行結果如下:

        Student Info: 

  ID:981036 

  Name:LiuMing 

  Age:18 

  Dep:CSD

 

 

            在這個例子中,我們首先定義了一個類Student,實現了Serializable介面 ,然後通過物件輸出流的writeObject()方法將Student物件儲存到檔案 data.ser中 。之後,通過對家輸入流的readObjcet()方法從檔案data.ser中讀出儲存下來的Student物件 。從執行結果可以看到,通過序列化機制,可以正確地儲存和恢復物件的狀態。 

三、序列化的注意事項 
1.序列化能儲存的元素 

            序列化只能儲存物件的非靜態成員交量,不能儲存任何的成員方法和靜態的成員變數,而且序列化儲存的只是變數的值,對於變數的任何修飾符都不能儲存。 

2.transient關鍵字 

            對於某些型別的物件,其狀態是瞬時的,這樣的物件是無法儲存其狀態的。例如一個Thread物件或一個FileInputStream物件 ,對於這些欄位,我們必須用transient關鍵字標明,否則編譯器將報措。 

            另外 ,序列化可能涉及將物件存放到 磁碟上或在網路上發達資料,這時候就會產生安全問題。因為資料位於Java執行環境之外,不在Java安全機制的控制之中。對於這些需要保密的欄位,不應儲存在永久介質中 ,或者不應簡單地不加處理地儲存下來 ,為了保證安全性。應該在這些欄位前加上transient關鍵字。

下面是java規範中對transient關鍵字的解釋:   
      The   transient   marker   is   not   fully   specified   by   The   Java   Language     Specification   but   is   used   in   object   serialization   to   mark   member   variables   that   should   not   be   serialized.

 

 以下是transient的一個應用舉例:



//LoggingInfo.java
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Date;
public class LoggingInfo implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private Date loggingDate = new Date();
private String uid;
private transient String pwd;
LoggingInfo(String user, String password) {
uid = user;
pwd = password;
}
public String toString() {
String password = null;
if (pwd == null) {
password = "NOT SET";
} else {
password = pwd;
}
return "logon info: \n   " + "user: " + uid + "\n   logging date : "
+ loggingDate.toString() + "\n   password: " + password;
}
public static void main(String[] args) {
LoggingInfo logInfo = new LoggingInfo("MIKE", "MECHANICS");
System.out.println(logInfo.toString());
try {
ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(
"logInfo.out"));
o.writeObject(logInfo);
o.close();
} catch (Exception e) {// deal with exception
}
// To read the object back, we can write
try {
ObjectInputStream in = new ObjectInputStream(new FileInputStream(
"logInfo.out"));
LoggingInfo logInfo1 = (LoggingInfo) in.readObject();
System.out.println(logInfo1.toString());
} catch (Exception e) {// deal with exception
}
}
}

相關文章