Serializable接口:
一個對象序列化的接口,一個類只有實現(xiàn)了Serializable接口轨淌,它的對象才能被序列化
一艳汽、什么是序列化壶愤?
【將對象的狀態(tài)信息轉(zhuǎn)換為可以存儲或傳輸?shù)男问降倪^程,在序列化期間乔夯,對象將其當前狀態(tài)寫入到臨時存儲區(qū)或持久性存儲區(qū)砖织,之后,便可以通過從存儲區(qū)中讀取或反序列化對象的狀態(tài)信息末荐,來重新創(chuàng)建該對象】
序列化將數(shù)據(jù)分解成字節(jié)流侧纯,以便存儲在文件中或在網(wǎng)絡上傳輸。
反序列化就是打開字節(jié)流并重構(gòu)對象甲脏。
二眶熬、什么情況下需要序列化?
【當我們需要把對象的狀態(tài)信息通過網(wǎng)絡進行傳輸块请,或者需要將對象的狀態(tài)信息持久化娜氏,以便將來使用時都需要把對象進行序列化】
三、Serializable主要用來支持兩種主要的特性:
1墩新、Java的RMI(remote method invocation)贸弥,RMI允許像在本機上一樣操作遠程機器上的對象,當發(fā)送消息給遠程對象時抖棘,就需要用到序列化機制來發(fā)送參數(shù)和接受返回值茂腥。
2、Java的JavaBean切省,Bean的狀態(tài)信息通常是在設計時配置的最岗,Bean的狀態(tài)信息必須被保存下來,以便當程序運行時能恢復這些狀態(tài)信息朝捆,這也需要序Serializable機制般渡。
只需要了解被序列化的類需要實現(xiàn) Serializable 接口,使用 ObjectInputStream 和 ObjectOutputStream 進行對象的讀寫。
四驯用、常出現(xiàn)的情景
1脸秽、兩個類A B代碼完全相同,試圖通過網(wǎng)絡傳遞對象數(shù)據(jù)蝴乔,A 端將對象 C 序列化為二進制數(shù)據(jù)再傳給 B记餐,B 反序列化得到 C。但一直反序列化不成功薇正。
解決:虛擬機是否允許反序列化片酝,不僅取決于類路徑和功能代碼是否一致,一個非常重要的一點是兩個類的序列化 ID 是否一致(就是 private static final long serialVersionUID = 1L)挖腰。雖然兩個類的功能代碼完全一致雕沿,但是序列化 ID 不同,他們無法相互序列化和反序列化猴仑。
I舐帧!A伤住<苍!榆苞!
序列化 ID 在 Eclipse 下提供了兩種生成策略稳衬,
(1)固定的 1L(一般這么做∽可以確保代碼一致時反序列化成功)
private static final long serialVersionUID = 1L;
(2)一個是隨機生成一個不重復的 long 類型數(shù)據(jù)(作用是:通過改變序列化 ID 可以用來限制某些用戶的使用薄疚。)
2、Facade外觀模式:
Client 端通過 Fa?ade Object 才可以與業(yè)務邏輯對象進行交互赊琳。而客戶端的 Fa?ade Object 不能直接由 Client 生成街夭,而是需要 Server 端生成,然后序列化后通過網(wǎng)絡將二進制對象數(shù)據(jù)傳給 Client躏筏,Client 負責反序列化得到 Fa?ade 對象板丽。
即 服務端(生成Facade object)序列化 ----->客戶端(反序列化,得到Facade對象趁尼,可用其與業(yè)務邏輯對象交互)
該模式可以使得 Client 端程序的使用需要服務器端的許可埃碱,同時 Client 端和服務器端的 Fa?ade Object 類需要保持一致。當服務器端想要進行版本更新時酥泞,只要將服務器端的 Fa?ade Object 類的序列化 ID 再次生成砚殿,當 Client 端反序列化 Fa?ade Object 就會失敗,也就是強制 Client 端從服務器端獲取最新程序芝囤。
3似炎、一個類實現(xiàn)了序列化辛萍,并且有其靜態(tài)變量。
但序列化保存的是對象的狀態(tài)羡藐,靜態(tài)變量屬于類的狀態(tài)贩毕,因此 序列化并不保存靜態(tài)變量。
4仆嗦、父類的序列化與transient:
父類不實現(xiàn)序列化辉阶,子類實現(xiàn)序列化,則將子類對象反序列化后輸出父類定義的某變量的數(shù)值欧啤,該變量數(shù)值與序列化時的數(shù)值不同睛藻。
原因:一個java對象的構(gòu)造必須先有父對象启上,再有子對象邢隧,反序列化也是,父類沒有實現(xiàn)序列化冈在,則虛擬機不會序列化父類倒慧。
解決:
a、父類也實現(xiàn)序列化
b包券、為父類創(chuàng)造默認的無參的構(gòu)造方法纫谅,在父類無參構(gòu)造方法中對父類進行變量初始化。則反序列化時溅固,構(gòu)造父對象時只能調(diào)用父類無參構(gòu)造函數(shù)為默認父對象付秕,如果不先在無參構(gòu)造函數(shù)中初始化變量,則父類變量值都會是默認聲明值侍郭,如0询吴,null。
所以亮元,使變量不被序列化的方法有:
a猛计、Transient 關鍵字的作用是控制變量的序列化,在變量聲明前加上該關鍵字爆捞,可以阻止該變量被序列化到文件中奉瘤,在被反序列化后,transient 變量的值被設為初始值煮甥,如 int 型的是 0盗温,對象型的是 null。
b成肘、可以將不需要被序列化的字段抽取出來放到父類中卖局,子類實現(xiàn)序列化,父類不實現(xiàn)艇劫,則父類的字段數(shù)據(jù)將不會被序列化吼驶。
5惩激、對敏感字段加密
服務端給客戶端發(fā)送序列化對象數(shù)據(jù),并在序列化時進行加密蟹演,客戶端用解密密鑰风钻,在反序列化時,對密碼讀取酒请,保證了序列化對象的數(shù)據(jù)安全骡技。
在序列化過程中,虛擬機會試圖調(diào)用對象類里的 writeObject 和 readObject 方法羞反,進行用戶自定義的序列化和反序列化布朦,如果沒有這樣的方法,則默認調(diào)用是 ObjectOutputStream 的 defaultWriteObject 方法以及 ObjectInputStream 的 defaultReadObject 方法昼窗。用戶自定義的 writeObject 和 readObject 方法可以允許用戶控制序列化的過程是趴,比如可以在序列化的過程中動態(tài)改變序列化的數(shù)值〕尉基于這個原理唆途,可以在實際應用中得到使用,用于敏感字段的加密工作。
如RMI技術(shù)。