Android序列化与反序列化
1. 什么是java序列化,如何實(shí)現(xiàn)java序列化?
我們有時(shí)候?qū)⒁粋€(gè)java對象變成字節(jié)流的形式傳出去或者從一個(gè)字節(jié)流中恢復(fù)成一個(gè)java對象,例如,要將java對象存儲到硬盤或者傳送給網(wǎng)絡(luò)上的其他計(jì)算機(jī),這個(gè)過程我們可以自己寫代碼去把一個(gè)java對象變成某個(gè)格式的字節(jié)流再傳輸,但是,JRE本身就提供了這種支持,我們可以調(diào)用OutputStream的writeObject()方法來做,如果要讓java 幫我們做,要被傳輸?shù)膶ο蟊仨殞?shí)現(xiàn)Serializable接口,這樣,javac編譯時(shí)就會進(jìn)行特殊處理,編譯的類才可以被writeObject()方法操作,這就是所謂的序列化。需要被序列化的類必須實(shí)現(xiàn)Serializable接口,該接口是一個(gè)mini接口,其中沒有需要實(shí)現(xiàn)的方法,implements Serializable只是為了標(biāo)注該對象是可被序列化的
例如,在web開發(fā)中,如果對象被保存在了Session中,tomcat在重啟時(shí)要把Session對象序列化到硬盤,這個(gè)對象就必須實(shí)現(xiàn)Serializable接口。如果對象要經(jīng)過分布式系統(tǒng)進(jìn)行網(wǎng)絡(luò)傳輸或通過rmi等遠(yuǎn)程調(diào)用,這就需要在網(wǎng)絡(luò)上傳輸對象,被傳輸?shù)膶ο缶捅仨殞?shí)現(xiàn)Serializable接口
2. Serializable
Serializable是一個(gè)javase標(biāo)記接口,會產(chǎn)生一個(gè)序列化值,該值跟bean的成員相關(guān),所以實(shí)現(xiàn)Serilizable接口的時(shí)候,必須給一個(gè)uid,否則,當(dāng)成員變化的時(shí)候,標(biāo)記值也會變化,再次讀取的時(shí)候也出現(xiàn)exception(要先重新write再read,但是write可能會讓之前的數(shù)據(jù)丟失)
注意事項(xiàng)
- 使用transient關(guān)鍵字聲明不需要序列化的成員變量
- 序列化數(shù)據(jù)后,再次修改類文件,讀取數(shù)據(jù)會出問題,如何解決呢?
3. Parcelable
因?yàn)镾erializable接口在序列化的時(shí)候會產(chǎn)生大量的臨時(shí)變量,效率較低,而Parcelable是android推出的高效序列化接口
public final class Rect implements Parcelable {public int left;public int top;public int right;public int bottom;public static final Parcelable.Creator<Rect> CREATOR = newParcelable.Creator<Rect>() {public Rect createFromParcel(Parcel in) {return new Rect(in);}public Rect[] newArray(int size) {return new Rect[size];}};public Rect() {}private Rect(Parcel in) {readFromParcel(in);}public void writeToParcel(Parcel out) {out.writeInt(left);out.writeInt(top);out.writeInt(right);out.writeInt(bottom);}public void readFromParcel(Parcel in) {left = in.readInt();top = in.readInt();right = in.readInt();bottom = in.readInt();} }Android Parcelable code generator
生成Parcelable代碼
4. Serialiable與Parcelable的區(qū)別
- 在使用內(nèi)存的時(shí)候,Parcelable 類比Serializable 性能高,首選使用Parcelable 類
- Serializable 在序列化的時(shí)候會產(chǎn)生大量的臨時(shí)變量,從而引起頻繁的GC
- 數(shù)據(jù)持久化,Parcelable 不能使用在要將數(shù)據(jù)存儲在磁盤上的情況。盡管Serializable 效率低點(diǎn),但在這種情況下,還是建議你用Serializable
Serializable是Java中的序列化接口,其使用起來簡單但是開銷很大,序列化和反序列化過程需要大量I/O操作。而Parcelable是Android中的序列化方式,因此,更適合用在Android平臺上,它的缺點(diǎn)就是用起來稍微麻煩點(diǎn),但是它的效率很高,這是Android推薦的序列化方式,因此,我們要首選Parcelable。Parcelable主要用在內(nèi)存序列化上,通過Parcelable將對象序列化到存儲設(shè)備中或者將對象序列化后通過網(wǎng)絡(luò)傳輸也都是可以的,但是這個(gè)過程會稍顯復(fù)雜,因此在這兩種情況下建議大家使用Parcelable。
5. 序列化流ObjectOutputStream
ObjectOutputStream 將 Java 對象的基本數(shù)據(jù)類型和圖形寫入 OutputStream。可以使用 ObjectInputStream 讀取(重構(gòu))對象。通過在流中使用文件可以實(shí)現(xiàn)對象的持久存儲。如果流是網(wǎng)絡(luò)套接字流,則可以在另一臺主機(jī)上或另一個(gè)進(jìn)程中重構(gòu)對象。
只能將支持 java.io.Serializable 接口的對象寫入流中。每個(gè) Serializable 對象的類都被編碼,編碼內(nèi)容包括類名和類簽名、對象的字段值和數(shù)組值,以及從初始對象中引用的其他所有對象的閉包。
writeObject() 方法用于將對象寫入流中。所有對象(包括 String 和數(shù)組)都可以通過 writeObject ()寫入。可將多個(gè)對象或基元寫入流中。必須使用與寫入對象時(shí)相同的類型和順序從相應(yīng) ObjectInputstream 中讀回對象。
還可以使用 DataOutput 中的適當(dāng)方法將基本數(shù)據(jù)類型寫入流中。還可以使用 writeUTF() 方法寫入字符串。
對象的默認(rèn)序列化機(jī)制寫入的內(nèi)容是:對象的類,類簽名,以及非瞬態(tài)和非靜態(tài)字段的值。其他對象的引用(瞬態(tài)和靜態(tài)字段除外)也會導(dǎo)致寫入那些對象。可使用引用共享機(jī)制對單個(gè)對象的多個(gè)引用進(jìn)行編碼,這樣即可將對象的圖形恢復(fù)為最初寫入它們時(shí)的形狀。
構(gòu)造方法
ObjectOutputStream()
為完全重新實(shí)現(xiàn) ObjectOutputStream 的子類提供一種方法,讓它不必分配僅由 ObjectOutputStream 的實(shí)現(xiàn)使用的私有數(shù)據(jù)。ObjectOutputStream(OutputStream out) :
創(chuàng)建寫入指定 OutputStream 的 ObjectOutputStream
6. 反序列化流ObjectInputStream
1、ObjectInputStream 對以前使用 ObjectOutputStream 寫入的基本數(shù)據(jù)和對象進(jìn)行反序列化。
2、ObjectOutputStream 和 ObjectInputStream 分別與 FileOutputStream 和 FileInputStream 一起使用時(shí),可以為應(yīng)用程序提供對對象圖形的持久存儲。ObjectInputStream 用于恢復(fù)那些以前序列化的對象。其他用途包括使用套接字流在主機(jī)之間傳遞對象,或者用于編組和解組遠(yuǎn)程通信系統(tǒng)中的實(shí)參和形參。
3、ObjectInputStream 確保從流創(chuàng)建的圖形中所有對象的類型與 Java 虛擬機(jī)中顯示的類相匹配。使用標(biāo)準(zhǔn)機(jī)制按需加載類。
4、只有支持 java.io.Serializable 或 java.io.Externalizable 接口的對象才能從流讀取。
5、readObject 方法用于從流讀取對象。應(yīng)該使用 Java 的安全強(qiáng)制轉(zhuǎn)換來獲取所需的類型。在 Java 中,字符串和數(shù)組都是對象,所以在序列化期間將其視為對象。讀取時(shí),需要將其強(qiáng)制轉(zhuǎn)換為期望的類型。
6、可以使用 DataInput 上的適當(dāng)方法從流讀取基本數(shù)據(jù)類型。
7、默認(rèn)情況下,對象的反序列化機(jī)制會將每個(gè)字段的內(nèi)容恢復(fù)為寫入時(shí)它所具有的值和類型。反序列化進(jìn)程將忽略聲明為瞬態(tài)或靜態(tài)的字段。對其他對象的引用使得根據(jù)需要從流中讀取這些對象。使用引用共享機(jī)制能夠正確地恢復(fù)對象的圖形。反序列化時(shí)始終分配新對象,這樣可以避免現(xiàn)有對象被重寫。
8、序列化操作問題:NotSerializableException:未序列化異常
9、為什么要實(shí)現(xiàn)序列化?如何實(shí)現(xiàn)序列化?
類通過實(shí)現(xiàn) java.io.Serializable 接口以啟用其序列化功能。未實(shí)現(xiàn)此接口的類將無法使其任何狀態(tài)序列化或反序列化。
該接口居然沒有任何方法,類似于這種沒有方法的接口被稱為標(biāo)記接口。
10、序列化數(shù)據(jù)后,再次修改類文件,讀取數(shù)據(jù)會出問題,如何解決呢?
每次修改java文件的內(nèi)容的時(shí)候,class文件的id值都會發(fā)生改變。而讀取文件的時(shí)候,會和class文件中的id值進(jìn)行匹配。所以,就會出問題。讓這個(gè)id值在java文件中是一個(gè)固定的值,這樣,你修改文件的時(shí)候,這個(gè)id值就不會發(fā)生改變。
我們要知道的是:看到類實(shí)現(xiàn)了序列化接口的時(shí)候,要想解決黃色警告線問題,就可以自動產(chǎn)生一個(gè)序列化id值。而且產(chǎn)生這個(gè)值以后,我們對類進(jìn)行任何改動,它讀取以前的數(shù)據(jù)是沒有問題的。
11、我一個(gè)類中可能有很多的成員變量,有些我不想進(jìn)行序列化。請問該怎么辦呢?
使用transient關(guān)鍵字聲明不需要序列化的成員變量
代碼示例:
7. Parcelable 接口和Serializable 接口的區(qū)別?
Parcelable 接口是基于Android 源生的提供的序列化接口,Serializable 接口是基于Java 源生提供的序列化接口。都可以將數(shù)據(jù)持久化到本地。但是在開發(fā)中經(jīng)常使用Serializable 接口,因?yàn)镻arcelable接口需要實(shí)現(xiàn)兩個(gè)方法,writeToParcel 和readFromParcel,比較麻煩。但是Android 源碼中會常用Parcelable接口,因?yàn)镻arcelable 接口更輕量級一些,更符合Android 的特性。
Intent 也實(shí)現(xiàn)了Parcelable 接口。所以它可以將數(shù)據(jù)進(jìn)行序列化和反序列化,并且可以開啟頁面,通過putExtra 將數(shù)據(jù)來回傳遞。
public class Intent implements Parcelable, Cloneable {// 省略代碼 }比如Person 大家都比較了解,Person 是對數(shù)據(jù)的封裝,它可以有name,age,sex 屬性,當(dāng)我們需要通過intent 來傳遞Person 對象的時(shí)候,需要讓Person 實(shí)現(xiàn)Parcelable 接口,通過putExtra(String name,Parcelable value)方法來傳遞。
Android序列化:Serializable & Parcelable
http://blog.csdn.net/axi295309066/article/details/53164604
總結(jié)
以上是生活随笔為你收集整理的Android序列化与反序列化的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Notification详解
- 下一篇: MySQL数据库:SQL语句