什么是序列化
有對象存儲在內(nèi)存中都是短暫的申尤,為了把對象狀態(tài)保存下來,就需要吧對象存儲到磁盤或者其他介質(zhì)中犹菇,這個過程就叫做序列化妹懒。先將對象的公共字段和私有字段以及類的名稱(包括類所在的程序集)轉(zhuǎn)換為字節(jié)流,然后再把字節(jié)流寫入數(shù)據(jù)流
什么是反序列化
反序列化是序列化的反操作野哭,就是將存儲在磁盤或者其他介質(zhì)的對象 反序列化(讀任对摺)
到內(nèi)存中,待我們內(nèi)存中使用
Serializble
Serializable 是Java 提供的空的序列化接口虐拓,專門為對象提供標準序列化和反序列的操作心俗。
使用Serializable實現(xiàn)類的序列化比較簡單,
只要在類聲明中實現(xiàn) Serializable 接口即可蓉驹,同時強烈建議聲明序列化標識城榛。
serialVersionUID
serialVersionUID是在序列化和反序列化表示 是否是同一版本的類。
實際上對象在序列化時會自動生成serialVersionUID态兴,但是為什么還要我們定義一個
原因:serialVersionUID是用來輔助序列化和反序列化過程的狠持,原則上序列化后的對象中serialVersionUID
只有和當前類的serialVersionUID相同才能夠正常被反序列化,也就是說序列化與反序列化的serialVersionUID
必須相同才能夠使序列化操作成功瞻润。具體過程是這樣的:序列化操作的時候系統(tǒng)會把當前類的serialVersionUID寫入到序列化文件中喘垂,當反序列化時系統(tǒng)會去檢測文件中的serialVersionUID,判斷它是否與當前類的serialVersionUID一致绍撞,如果一致就說明序列化類的版本與當前類版本是一樣的正勒,可以反序列化成功,否則失敗傻铣。報出如UID錯誤章贞。如果不指定的話只要這個文件多
一個空格,系統(tǒng)自動生成的UID就會截然不同的非洲,反序列化也就會失敗
1.如果反序列類的成員變量的類型或者類名鸭限,發(fā)生了變化,那么即使serialVersionUID相同也 無法正常反序列化成功
2.靜態(tài)成員變量屬于類不屬于對象两踏,不會參與序列化過程败京,使用transient關鍵字標記的成員變量也不參與序列化過程
控制系統(tǒng)的默認序列化和反序列過程
public class User implements Serializable {
private static final long serialVersionUID = -4083503801443301445L;
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
* 序列化時,
* 首先系統(tǒng)會先調(diào)用writeReplace方法,在這個階段,
* 可以進行自己操作,將需要進行序列化的對象換成我們指定的對象.
* 一般很少重寫該方法
*/
private Object writeReplace() throws ObjectStreamException {
System.out.println("writeReplace invoked");
return this;
}
/**
*接著系統(tǒng)將調(diào)用writeObject方法,
* 來將對象中的屬性一個個進行序列化,
* 我們可以在這個方法中控制住哪些屬性需要序列化.
* 這里只序列化name屬性
*/
private void writeObject(java.io.ObjectOutputStream out) throws IOException {
System.out.println("writeObject invoked");
out.writeObject(this.name == null ? "默認值" : this.name);
}
/**
* 反序列化時,系統(tǒng)會調(diào)用readObject方法,將我們剛剛在writeObject方法序列化好的屬性,
* 反序列化回來.然后通過readResolve方法,我們也可以指定系統(tǒng)返回給我們特定的對象
* 可以不是writeReplace序列化時的對象,可以指定其他對象.
*/
private void readObject(java.io.ObjectInputStream in) throws IOException,
ClassNotFoundException {
System.out.println("readObject invoked");
this.name = (String) in.readObject();
System.out.println("got name:" + name);
}
/**
* 通過readResolve方法,我們也可以指定系統(tǒng)返回給我們特定的對象
* 可以不是writeReplace序列化時的對象,可以指定其他對象.
* 一般很少重寫該方法
*/
private Object readResolve() throws ObjectStreamException {
System.out.println("readResolve invoked");
return this;
}
}
Parcelable
鑒于Serializable在內(nèi)存序列化上開銷比較大,而內(nèi)存資源屬于android系統(tǒng)中的稀有
資源(android系統(tǒng)分配給每個應用的內(nèi)存開銷都是有限的)梦染,為此android中提供了Pa
rcelable接口來實現(xiàn)序列化操作赡麦,Parcelable的性能比Serializable好,在內(nèi)存開銷方
面較小弓坞,所以在內(nèi)存間數(shù)據(jù)傳輸時推薦使用Parcelable隧甚,
Parcelable與Serializable 區(qū)別
- 存儲媒介不同
Seriaizable 使用IO讀寫存儲的硬盤上
Parcelable 直接在內(nèi)存中讀寫
很明顯內(nèi)存的讀寫速度通常大于IO讀寫车荔,所以在Android中通常優(yōu)先選擇Parcelable渡冻。
- 序列化方式不同
Serializable 使用反射,序列化和反序列化需要使用大量IO操作
Parcelable 自己實現(xiàn)封裝傳送和解封接收忧便,數(shù)據(jù)存放在內(nèi)存中族吻,因此效率快的多