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