一. Serializable接口
該方法使用簡單,只需要將類實現(xiàn)Serializable接口并聲明一個serialVersionUID即可(serialVersionUID非必須,但建議)。
原因:為了避免因為增刪一些成員變量,導(dǎo)致反序列化失敗,建議手動指定serialVersionUID的值;如果類結(jié)構(gòu)發(fā)生毀滅性改變,即便serialVersionUID驗證通過,也會反序列化失敗。
serialVersionUID的工作機(jī)制:序列化的時候系統(tǒng)會把當(dāng)前類的serialVersionUID寫入序列化的文件中(也可能是其他中介),當(dāng)反序列化的時候系統(tǒng)就會去檢測文件中的serialVersionUID,看它是否和當(dāng)前類的serialVersionUID一致,如果一致就說明序列化的類的版本和當(dāng)前類的版本是相同的,這個時候就可以成功反序列化;否則就說明當(dāng)前類和序列化的類相比發(fā)生了變化,比如成員變量的數(shù)量、類型發(fā)生了改變,這時是無法正常反序列化的,會有異常InvalidClassException。
注意:
- 靜態(tài)成員變量屬于類不屬于對象,不會參與序列化過程;
- 用transient關(guān)鍵字標(biāo)記的成員變量不參與序列化過程。
二. Parcelable接口
該方法使用起來麻煩一些,需要實現(xiàn)序列化、反序列化和內(nèi)容描述等功能。
| 方法 | 功能 |
|---|---|
| createFromParcel(Parcel in) | 從序列化后的對象中創(chuàng)建原始對象 |
| new Array(int size) | 創(chuàng)建指定長度的原始對象數(shù)組 |
| User(Parcel in) | 從序列化后的對象中創(chuàng)建原始對象 |
| writeToParcel(Parcel dest, int flags) | 將當(dāng)前對象寫入序列化結(jié)構(gòu)中,其中flag表示有兩種值:0或者1。為1時標(biāo)識當(dāng)前對象需要作為返回值返回,不能立即釋放資源,幾乎所有情況都為0 |
| describeContents | 返回當(dāng)前對象的內(nèi)容描述。如果含有文件掃描符,返回1,否則返回0。幾乎所有情況都為0 |
注意:
在以Parcel為參的構(gòu)造函數(shù)中,如果有一個變量是可序列化對象,那么它的反序列化過程需要傳遞當(dāng)前線程的上下文類加載器,否則會報無法找到類的錯誤。
book = in.readParcelable(Thread.currentThread().getContextClassLoader());
對比:
Serializable是Java中的序列化接口,使用簡單但開銷很大,序列化和反序列化過程都需要大量的I/O操作;Parcelable是Android中的序列化方式,更適用于Android平臺,效率很高,但使用起來稍微麻煩點。內(nèi)存序列化上,首選Parcelable;將對象序列化到存儲設(shè)備或通過網(wǎng)絡(luò)傳輸時,建議使用Serializable。