對象的串行化(Serialization)
壹、串行化的概念和目的?
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如下:
import?java.io.Serializable;public?class?Student?implements?Serializable?{
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;
}
}
2.構造對象的輸入/輸出流?
要串行化壹個對象,必須與壹定的對象輸出/輸入流聯系起來,通過對象輸出流將對象狀態保存下來,再通過對象輸入流將對象狀態恢復。?
java.io包中,提供了ObjectInputStream和ObjectOutputStream將數據流功能擴展至可讀寫對象 。在ObjectInputStream 中用readObject()方法可以直接讀取壹個對象,ObjectOutputStream中用writeObject()方法可以直接將對象保存到輸出流中。
import?java.io.FileInputStream;import?java.io.FileOutputStream;
import?java.io.IOException;
import?java.io.ObjectInputStream;
import?java.io.ObjectOutputStream;
public?class?ObjectSer?{
public?static?void?main(String?args[])?throws?IOException,
ClassNotFoundException?{
Student?stu?=?new?Student(981036,?"LiuMing",?18,?"CSD");
FileOutputStream?fo?=?new?FileOutputStream("data.ser");
ObjectOutputStream?so?=?new?ObjectOutputStream(fo);
try?{
so.writeObject(stu);
so.close();
}?catch?(IOException?e)?{
System.out.println(e);
}
stu?=?null;
FileInputStream?fi?=?new?FileInputStream("data.ser");
ObjectInputStream?si?=?new?ObjectInputStream(fi);
try?{
stu?=?(Student)?si.readObject();
si.close();
}?catch?(IOException?e)
{
System.out.println(e);
}
System.out.println("Student?Info:");
System.out.println("ID:"?+?stu.id);
System.out.println("Name:"?+?stu.name);
System.out.println("Age:"?+?stu.age);
System.out.println("Dep:"?+?stu.department);
}
}
運行結果如下:
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.javaimport?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?+?"\nlogging?date?:?"+?loggingDate.toString()?+?"\npassword:?"?+?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
}
}
}