由于進行通信肯定要涉及數(shù)據(jù)的處理劲适,所以我們需要先了解兩個基礎(chǔ)的概念,序列化和反序列化酪捡。
定義
序列化:將對象轉(zhuǎn)化為可保存的字節(jié)序列(注意是對象)狞山;
反序列:將字節(jié)序列恢復(fù)為對象的過程纸泡。
序列化和反序列的用途:
1.以某種存儲形式使自定義對象序列化并永久的保存對象數(shù)據(jù)(將對象數(shù)據(jù)保存在文件當中,或者是磁盤中)陈症;
2.序列化對象的時候只是針對變量進行序列化,不針對方法進行序列化蔼水;
3.通過序列化操作將對象數(shù)據(jù)在網(wǎng)絡(luò)上進行傳輸(由于網(wǎng)絡(luò)傳輸是以字節(jié)流的方式對數(shù)據(jù)進行傳輸?shù)?因此序列化的目的是將對象數(shù)據(jù)轉(zhuǎn)換成字節(jié)流的形式);
4.通過序列化在進程間傳遞對象录肯;
5.Java平臺允許我們在內(nèi)存中創(chuàng)建可復(fù)用的Java對象趴腋,但一般情況下,只有當JVM處于運行時论咏,這些對象才可能存在优炬,即,這些對象的生命周期不會比JVM的生命周期更長(即每個對象都在JVM中)但在現(xiàn)實應(yīng)用中厅贪,就可能要停止JVM運行蠢护,但有要保存某些指定的對象,并在將來重新讀取被保存的對象养涮。這是Java對象序列化就能夠?qū)崿F(xiàn)該功能葵硕。(可選擇入數(shù)據(jù)庫、或文件的形式保存)贯吓;
序列化方式
Serializable
Serializable是Java提供的一個序列化接口懈凹,他是一個空接口,類實現(xiàn)該接口即可實現(xiàn)序列化宣决。
在實現(xiàn)Serializable時候蘸劈,編譯器會提示,讓我們添加serialVersionUID字段尊沸,該字段是一個關(guān)鍵的字段
相應(yīng)的實現(xiàn)好了威沫,那么如何寫入和讀取呢?
寫入:
public void writeSerializable() {
try {
// 構(gòu)造對象
Book book = new Book();
// 構(gòu)造序列化輸出字節(jié)流
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("xxx.txt"));
// 序列化對象
oos.writeObject(book);
// 關(guān)閉流 oos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
讀韧葑ā:
public void readSerializable() {
try {
// 創(chuàng)建序列化讀取字節(jié)流
ObjectInputStream ois = new ObjectInputStream(new FileInputStream( "xxx.txt"));
// 反序列化(讀劝袈印)對象
Book book = (Book) ois.readObject();
// 關(guān)閉流 ois.close();
} catch (Exception e) {
e.printStackTrace();
}
}
在序列化時,如果我們序列化對象之后屁商,改變了我們的類結(jié)構(gòu)(添加或改變字段)烟很,甚至是修改了字段的類型,修改了類名蜡镶,那么我們能反序列化成功嗎雾袱。那么關(guān)鍵就在于serialVersionUID字段。
如果我們不指定的話官还。在序列化時芹橡,會計算當前類結(jié)構(gòu)的hash值并賦給serialVersionUID,當反序列時望伦,會比對該值是否相同林说,如果不相同煎殷,則無法序列化成功。
我們也可以手動指定腿箩,手動指定的好處是在類結(jié)構(gòu)發(fā)生變化時豪直,能夠最大程度的反序列,當然前提是只是刪除或添加了字段珠移,如果是變量類型發(fā)生了變化弓乙,則依然無法反序列成功。
serialVersionUID 的工作機制:
序列化時系統(tǒng)會把當前類的serialVersionUID寫入序列化文件中钧惧,當反序列化時候系統(tǒng)會去檢測文件中的serialVersionUID,看它是否和當前類的serialVersionUID一致唆貌,如果一致說明序列化類的版本和當前類的版本是相同的,這個時候可以成功反序列化垢乙,否則就說明當前類和序列化的類相比發(fā)生了某些變化锨咙。所以,我們最好指定serialVersionUID追逮,避免他自定生成酪刀。
Parcelable
Parcelable是Android中特有的一種序列化方式,在intent傳值時钮孵,通常使用該方式骂倘。該方式實現(xiàn)序列化,依然實現(xiàn)Parcelable巴席,然后實現(xiàn)一些該接口的方法历涝。
Parcelable實現(xiàn)兩個方法,創(chuàng)建一個字段:
實現(xiàn)describeContents():返回當前對象的內(nèi)容描述漾唉。幾乎所有情況下都是返回0荧库。
實現(xiàn)public void writeToParcel(Parcel dest, int flags):將當前對象寫入到序列化結(jié)構(gòu)中
構(gòu)造Parcelable.Creator字段,該對象需要實現(xiàn)兩個方法:
public Book createFromParcel(Parcel source):從序列化后的對象中創(chuàng)建原始的值赵刑。
public Book[] newArray(int size):創(chuàng)建指定長度的原始對象數(shù)組分衫。
Serializable和Parcelable的比較
1.Serializable是Java中的序列化接口,其使用起來簡單但是開銷較大般此,序列化和反序列化需要大量的I/O操作蚪战。
2.Parcelable是Android中的序列化方式,更適用于Android的平臺上铐懊,他的缺點是使用起來稍微麻煩邀桑,但是效率很高。
3.Parcelable適合進程間的通信科乎,運行期壁畸。Serializable適合文件存儲即網(wǎng)絡(luò)傳輸。
4.Serializable序列化不保存靜態(tài)變量喜喂,可以使用Transient關(guān)鍵字對部分字段不進行序列化瓤摧,也可以覆蓋writeObject、readObject方法以實現(xiàn)序列化過程自定義
5.內(nèi)存間數(shù)據(jù)傳輸時推薦使用Parcelable玉吁,如activity間傳輸數(shù)據(jù)照弥,而Serializable可將數(shù)據(jù)持久化方便保存,所以在需要保存或網(wǎng)絡(luò)傳輸數(shù)據(jù)時選擇Serializable
參考
Android IPC 進程間通信