序列化

序列化

序列化(Serialization)是將對象的狀態信息轉換為可以存儲或傳輸的形式的過程。在序列化期間,對象將其當前狀態寫入到臨時或持久性存儲區。以後,可以通過從存儲區中讀取或反序列化對象的狀態,重新創建該對象。

序列化使其他代碼可以查看或修改,那些不序列化便無法訪問的對象實例數據。確切地說,代碼執行序列化需要特殊的許可權:即指定了SerializationFormatter標誌的SecurityPermission。在默認策略下,通過Internet下載的代碼或Internet代碼不會授予該許可權;只有本地計算機上的代碼才被授予該許可權。

通常,對象實例的所有欄位都會被序列化,這意味著數據會被表示為實例的序列化數據。這樣,能夠解釋該格式的代碼有可能能夠確定這些數據的值,而不依賴於該成員的可訪問性。類似地,反序列化從序列化的表示形式中提取數據,並直接設置對象狀態,這也與可訪問性規則無關。

徠對於任何可能包含重要的安全性數據的對象,如果可能,應該使該對象不可序列化。如果它必須為可序列化的,請嘗試生成特定欄位來保存不可序列化的重要數據。如果無法實現這一點,則應注意該數據會被公開給任何擁有序列化許可權的代碼,並確保不讓任何惡意代碼獲得該許可權。

目的


1、以某種存儲形式使自定義對象持久化;
2、將對象從一個地方傳遞到另一個地方。
3、使程序更具維護性。

技術


*二進位序列化保持類型保真度,這對於在應用程序的不同調用之間保留對象的狀態很有用。例如,通過將對象序列化到剪貼板,可在不同的應用程序之間共享對象。您可以將對象序列化到流、磁碟、內存和網路等等。遠程處理使用序列化“通過值”在計算機或應用程序域之間傳遞對象。
*XML序列化僅序列化公共屬性和欄位,且不保持類型保真度。當您要提供或使用數據而不限制使用該數據的應用程序時,這一點是很有用的。由於XML是一個開放式標準,因此,對於通過Web共享數據而言,這是一個很好的選擇。SOAP同樣是一個開放式標準,這使它也成為一個頗具吸引力的選擇。

PHP


注:徠在php3中,在序列化和解序列化的過程中對象會失去類的關聯。結果的變數是對象類型,但是沒有類和方法,因此就沒什麼用了(就好像一個用滑稽的語法定義的數組一樣)。
serialize()返回一個字元串,包含著可以儲存於php的任何值的位元組流表示。unserialize()可以用此字元串來重建原始的變數值。用序列化來保存對象可以保存對象中的所有變數。對象中的函數不會被保存,只有類的名稱。
要能夠unserialize()一個對象,需要定義該對象的類。也就是,如果序列化了page1.php中類A的對象$a,將得到一個指向類A的字元串並包含有所有$a中變數的值。如果要在page2.php中將其解序列化,重建類A的對象$a,則page2.php中必須要出現類A的定義。例如可以這樣實現,將類A的定義放在一個包含文件中,並在page1.php和page2.php都包含此文件。
one;}}//page1.php:include("classa.inc");$a=newA;$s=serialize($a);//將$s存放在某處使page2.php能夠找到$fp=fopen("store","w");fwrite($fp,$s);fclose($fp);//page2.php://為了正常解序列化需要這一行include("classa.inc");$s=implode("",@file("store"));$a=unserialize($s);//現在可以用$a對象的show_one()函數了$a->show_one();?>
如果在用會話並使用了session_register()來註冊對象,這些對象會在每個php頁面結束時被自動序列化,並在接下來的每個頁面中自動解序列化。基本上是說這些對象一旦成為會話的一部分,就能在任何頁面中出現。
強烈建議在所有的頁面中都包括這些註冊的對象的類的定義,即使並不是在所有的頁面中都用到了這些類。如果沒有這樣做,一個對象被解序列化了但卻沒有其類的定義,它將失去與之關聯的類並成為stdClass的一個對象而完全沒有任何可用的函數,這樣就很沒有用處。
因此如果在以上的例子中$a通過運行session_register("a")成為了會話的一部分,應該在所有的頁面中包含classa.inc文件,而不只是page1.php和page2.php。

Java編程中


序列化的實現方法
把一個Java對象寫入到硬碟或者傳輸到網路上面的其它計算機,這時我們就需要自己去通過java把相應的對象寫成轉換成位元組流。對於這種通用的操作,我們為什麼不使用統一的格式呢?沒錯,這裡就出現了java的序列化的概念。在Java的OutputStream類下面的子類ObjectOutputStream類就有對應的WriteObject(Object object) 其中要求對應的object實現了java的序列化的介面。
在使用tomcat開發JavaEE相關項目的時候,我們關閉tomcat后,相應的session中的對象就存儲在了硬碟上,如果我們想要在tomcat重啟的時能夠從tomcat上面讀取對應session中的內容,那麼保存在session中的內容就必須實現相關的序列化操作,還有jdbc載入驅動用的就是反序列化,將字元串變為對象。
序列化操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class Book implements Serializable{
//序列化類:java.ioObjectOutputStream講對象變為指定的二進位數據
private static final long serialVersionUID = 1L;
private String title;
private double price;
public Book(String tit,double pri){
this.title=tit;
this.price=pri;
}
public String toString() {
Map hashMap = new HashMap();
hashMap.put("Computer base", "6.2");
hashMap.put("Computer webpage", "45.2");
hashMap.put("Java", "105.2");
hashMap.put("Andriod", "89.2");
//第一種:使用keySet()方法遍歷哈希表hashMap中的一些元素
System.out.println("通過keySet()方法遍歷key和value:");
Set keys = hashMap.keySet();
for (String key : keys) {
String value= hashMap.get(key);
System.out.println("BookName:"+ key + " ,BookPrice:" + value);
}
return "BookName:"+this.title+" ,BookPrice:"+this.price;
}
}
反序列化
將二進位數據換回原對象,構造方法:ObjectInputStream(InputStream in),方法: Object readObject() 從 ObjectInputStream 讀取對象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Serialization {
public static File file = null;
public static void main(String[] args) throws Exception, IOException {
file = new File("serialize.doc");
//序列化到指定的文本
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(file));
oos.writeObject(new Book("Java Development",45.3));
oos.flush();
oos.close();
file = new File("serialize.doc");
//反序列化到指定的文本
ObjectInputStream ois=new ObjectInputStream(new FileInputStream(file));
Object obj=ois.readObject();
Book book=(Book) obj;
System.out.println("\n By using the byte stream serialization operation, "
+ "we can see the following information:\n"+book);
ois.close();
}
}
無序列化
類某些屬性不需要序列化,以上序列化和反序列化實現了的對象序列化,但是可以發現,操作時是將整個對象的所有屬性序列化,那麼transient關鍵字可以將某些內容不需要保存,就可以通過transient關鍵字來定義:private transient String title;此時title屬性無法被序列化