Java Serializable 點滴經驗
Serializable:可序列化的。
對象的序列化(Serialization)
序列化的定義
1. 什麼是序列化
對象的壽命通常隨著產生該對象的程式的終止而終止。有時候,可能需要將對象的狀態儲存下來,在需要時再將對象恢複。我們把對象的這種能記錄自己的狀態以便將來再生的能力,叫做對象的持久性(persistence)。對象通過寫出描述自己狀態的數值來記錄自己,這個過程叫對象的序列化(Serialization)。
2. 序列化的目的
序列化的目的是為java的運行環境提供一組特性,其主要任務是寫出對象執行個體變數的數值。來源:www.examda.com
序列化方法
在java.io包中,介面Serializable用來作為實現對象序列化的工具,只有實現了Serializable的類的對象才可以被序列化。
1. 定義一個可序列化對象
public class Student implements Serializable{
private static final long serialVersionUID = 1L;
int id;
String name;
int age;
String department ;//系別
public Student(int id,String name,int age,String department){
this.id = id;
this.name = name;
this.age = age;
this.department = department;
}
}
序列化運行時使用一個稱為 serialVersionUID 的版本號碼與每個可序列化類別相關聯,該序號在還原序列化過程中用於驗證序列化對象的寄件者和接收者是否為該對象載入了與序列化相容的類。如果接收者載入的該對象的類的 serialVersionUID 與對應的寄件者的類的版本號碼不同,則還原序列化將會導致 InvalidClassException。可序列化類別可以通過聲明名為 "serialVersionUID" 的欄位(該欄位必須是靜態 (static)、最終 (final) 的 long 型欄位)顯式聲明其自己的 serialVersionUID:
private static final long serialVersionUID = 1L;如果可序列化類別未顯式聲明 serialVersionUID,則序列化運行時將基於該類的各個方面計算該類的預設 serialVersionUID 值,如“Java(TM) 對象序列化規範”中所述。不過,強烈建議 所有可序列化類別都顯式聲明 serialVersionUID 值,原因計算預設的 serialVersionUID 對類的詳細資料具有較高的敏感性,根據編譯器實現的不同可能千差萬別,這樣在還原序列化過程中可能會導致意外的 InvalidClassException。因此,為保證 serialVersionUID 值跨不同 java 編譯器實現的一致性,序列化類別必須聲明一個明確的 serialVersionUID 值。還強烈建議使用 private 修改器顯示聲明 serialVersionUID(如果可能),原因是這種聲明僅應用於立即聲明類 -- serialVersionUID 欄位作為繼承成員沒有用處。
2. 構造對象的輸入/輸出流
要序列化一個對象,必須與一定的對象輸入/輸出流聯絡起來,通過對象輸出資料流將對象狀態儲存下來,再通過對象輸入資料流將對象狀態恢複。
java.io包中,提供了ObjectInputStream和ObjectOutputStream將資料流功能擴充至可讀寫對象。在ObjectInputStream中用readObject()方法可以直接讀取一個對象,ObjectOutputStream中用writeObject()方法可以直接將對象儲存到輸出資料流中。來源:www.examda.com
public static void main(String []args){
System.out.println("進入主方法了。。。");
Student stu=new Student(981036,"Liu Sui",18, "CSD");
//儲存對象的狀態
try{
FileOutputStream fo = new FileOutputStream("data.ser");
ObjectOutputStream so = new ObjectOutputStream(fo);
so.writeObject(stu);
so.close();
}catch(IOException e ) {
e.printStackTrace();
}
//恢複對象的狀態
try{
FileInputStream fi=new FileInputStream("data.ser");
ObjectInputStream si=new ObjectInputStream(fi);
try {
stu=(Student)si.readObject();
System.out.println("student id="+stu.id);
System.out.println("student name="+stu.name);
System.out.println("student age="+stu.age);
System.out.println("student department="+stu.department);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
si.close();
}catch(IOException e ) {
e.printStackTrace();
}
}
在這個例子中,我們首先定義一個類Student,實現了 Serializable介面,然後通過對象輸出資料流的writeObject()方法將Student對象儲存到檔案data.ser中。之後,通過對象輸入資料流的readObject()方法從檔案data.ser中讀出儲存下來的Student對象。
序列化的注意事項
1.序列化能儲存的元素
只能儲存對象的非靜態成員變數,不能儲存任何的成員方法和靜態成員變數,而且序列化儲存的只是變數的值,對於變數的任何修飾符,都不能儲存。
2.transient(短暫的, 瞬時的)關鍵字
對於某些類型的對象,其狀態是瞬時的,這樣的對象是無法儲存其狀態的,例如一個Thread對象,或一個FileInputStream對象,對於這些欄位,我們必須用transient關鍵字標明
3. 定製序列化
預設的序列化機制,對象序列化首先寫入類資料和類欄位的資訊,然後按照名稱的上升排列順序寫入其數值。如果想自己明確地控制這些數值的寫入順序和寫入種類,必須定義自己的讀取資料流的方式。就是在類的定義中重寫writeObject()和readObject()方法。
例如可在例子中,加入重寫的writeObject()和readObject()方法,對Student 類定製其序列化。
private void writeObject(ObjectOutputStream out)throws IOException
{
out.writeInt(id);
out.writeInt(age);
out.writeUTF(name);
out.writeUTF(department);
}
private void readObject(ObjectInputStream in)throws IOException
{
id=in.readInt();
age=in.readInt();
name=in.readUTF();
department=in.readUTF();
}
public class Student implements Serializable{
}說白了就是:
實現了Serializable介面的對象轉換為位元組序列,這些位元組序列可以被完全儲存以備以後重建原來的對象。也就是就是可以把對象存到位元組流,然後可以恢複!所以你想如果你的對象沒實現序列化怎麼才能進行網路傳輸呢,要網路傳輸就得轉為位元組流,所以在分布式應用中,你就得實現序列化,如果你不需要分布式應用,那就沒那個必要實現序列化.