Android 序列化 & 反序列化

###What? 何爲序列化與反序列化?數組

***序列化:***將對象轉化爲二進制序列的過程網絡

***反序列化:***將二進制序列恢復爲原始對象的過程數據結構

###Why? 爲何須要序列化? 因爲在系統底層,數據以簡單的字節序列形式進行傳遞,即在底層,系統不認識對象,只認識字節序列,因此爲了達到跨進程通信的目的,須要先對數據進行序列化;其次,在進行網絡數據傳輸或者activity間對象傳遞時,也須要先將對象轉化爲字節序列。加密

###How? 如何進行序列化? 在Android中,序列化操做有兩種方式:實現Serializabale接口或實現Parcelable接口。對象

Serializabale接口 Serializabale接口是一個空接口,實際上只提供標記的功能,標記實現了該接口的對象是能夠進行序列化的,而具體的序列化與反序列化操做是由ObjectOutputStream和ObjectInputStream完成的。序列化與反序列化過程均對用戶透明,其中須要保存許多額外的字段以保證反序列化過程可以順利完成,同時,在這個過程當中,還涉及到Java反射機制,因此總體時空開銷比較大。接口

Parcelable接口 Parcelable是Android提供的接口,它主要是經過writeToParcel(),將須要持久化的字段保存到一個Parcel對象裏面,而後經過CREATOR從Parcel對象中,取出相應的字段,完成對象的恢復過程。這整個過程均由用戶本身控制,能夠自定義保存和恢復的字段,因此存儲代價小不少。進程

Serializabale VS Parcelable 實際開發中,推薦使用Parcelable接口,理由大體有以下三點:首先,Parcelable接口是Android提供使用的,Google提供了比較好的文檔和技術支持;其次,Parcelable接口底層是內存的copy,而Serializable底層是文件IO操做,同時會使用到反射技術,因此效率上,Parcelable要遠高於Serializable;最後,Parcelable具備更好地可控性,咱們能夠本身控制須要保存和恢復的字段,同時節省空間開銷。Parcleable主要用於內存序列化,經過Parcelable將對象序列化到存儲設備中或者將對象序列化後經過網絡進行傳輸也是能夠的,可是這個過程會稍顯複雜,因襲在這兩種狀況下,建議使用Serializable。內存

###序列化相關知識開發

  1. 序列化 ID 當經過實現Serializable接口實現類的序列化操做時,須要提供一個序列化ID,即聲明private static final long serialVersionUID,原則上序列化後的數據中的serialVersionUID只有和當前類的serialVersionUID相同時,纔可以進行正常的反序列化操做,不然反序列化過程會失敗。serialVersionUID的詳細工做機制爲:序列化的時候,系統會將當前類的serialVersionUID寫入序列化文件/指定文件中,當反序列化的時候,系統會檢測文件中的serialVersionUID與當前類中的serialVersionUID是否一致,若一致,說明序列化的類的版本與當前類的版本相同,這個時候能夠成功進行反序列化操做;不然,說明當前類和序列化的類相比,發生了某些變化,如成員變量的數量、類型等發生變化,這時反序列化操做就沒法正常完成。文檔

  2. 靜態變量序列化 靜態變量是類變量,不屬於某個對象,而序列化操做保存的是對象的狀態,即對象的成員變量,因此靜態變量不會參與序列化過程。

  3. 父類的序列化 若是但願一個類的父類也被序列化,則該父類也應實現序列化接口。

  4. Transient 關鍵字 Transient用於聲明一個變量不參與序列化過程,因此當但願某些變量不被序列化時,就可使用該關鍵字修飾這些變量。被Transient關鍵字聲明的變量,在反序列化時,會被設置爲初始值,即int類型變量爲0,對象類型變量爲null。

  5. 對敏感字段加密 在消息傳輸的過程當中,有些字段是敏感字段,不但願被泄露,如用戶密碼等,在這種狀況下,進行序列化操做時,應先對敏感字段進行加密操做,反序列化時再進行解密。具體解決辦法爲:重寫類中的writeObject和readObject方法。由於在序列化過程當中,虛擬機會先調用待序列化類中的writeObject和readObject方法,若該方法存在,則使用該方法完成用戶自定義的序列化和反序列化操做,不然,調用 ObjectOutputStream 的 defaultWriteObject 方法以及 ObjectInputStream 的 defaultReadObject 方法進行默認的序列化和反序列化操做。

  6. 序列化存儲規則 Java 序列化機制爲了節省磁盤空間,具備特定的存儲規則,當對同一對象進行屢次序列化操做時,並不會對該對象的內容進行屢次存儲,而只存儲多份引用,這樣就只須要保存新增的引用及一些控制信息。

###ArrayList的序列化

ArrayList的定義

ArrayList保存內容的數組 由上圖一可知,ArrayList實現了Serializable接口,能夠進行序列化操做,而由圖二可知,其中保存內容的數組array被transient關鍵字修飾,不會被序列化,那麼問題來了,這究竟是咋回事呢? 緣由以下圖三所示:

圖三 ArrayList內部實現了writeObject和readObject方法,經過這兩個方法本身控制序列化過程。 Why transient? ArrayList爲何使用transient使array不被序列化,而後又自定義序列化過程呢? 由於ArrayList是一個動態數組,常常會成倍自增加長度,當數組中實際存放的元素不多,而申請的長度比較大時,直接進行序列化,就會生成不少null元素,因此爲了不沒必要要的null元素的生成,及提升時空效率,ArrayList將array用transient關鍵字進行聲明,而後再本身控制元素的序列化過程。

###總結

  1. 在進行跨進程通訊、activity間數據傳輸以及網絡數據傳輸時,須要將原始的對象類型轉化爲字節序列,這是就須要使用到對象的序列化與反序列化操做;
  2. 序列化即將對象或數據結構轉化爲字節序列的過程;反序列化即將字節序列恢復爲原始對象的過程;序列化保存的是對象的「狀態」,即對象的成員變量,因此靜態變量、靜態方法等屬於類的屬性以及被transient關鍵字聲明的不用於序列化的屬性,均不會被序列化;
  3. Android中序列化操做有兩種方式:實現Serializable接口和實現Parcleable接口。Serialiable是Java提供的序列化接口,使用起來比較簡單,可是開銷很大,序列化和反序列化均須要大量I/O操做,而Parcelable是Android提供的序列化方式,所以更適合用於Android平臺,因此在Android平臺上,首選Parcelable接口。
  4. ArrayList的序列化過程比較特殊,須要注意。
相關文章
相關標籤/搜索