前言
本博客對Java序列化反序列化、Serializable、Parcelable 知識的一個總結。在開發中我們發現Android中Intent傳遞對象有兩種方法:一是Bundle.putSerializable(Key,Object),另一種是Bundle.putParcelable(Key,Object)。當然這些Object是有一定的條件的,前者是實現了Serializable接口,而後者是實現了Parcelable接口。
一、java序列化、反序列化
推薦博文:java序列化、反序列化
1、定義:
Java序列化是指把Java對象轉換爲字節流的過程;而Java反序列化是指把字節流恢復爲Java對象的過程。
2.爲什麼需要序列化與反序列化?
1)永久性保存對象,保存對象的字節序列到本地文件中;
2)通過序列化對象在網絡中傳遞對象;
3)通過序列化在進程間傳遞對象。
3、如何實現Java序列化與反序列化
JDK類庫中序列化API
- java.io.ObjectOutputStream:對象輸出流
它的writeObject(Object obj)方法可以對object對象進行序列化,把得到的字節流寫到一個目標輸出流中。 - java.io.ObjectInputStream:對象輸入流,它的readObject()方法在輸入流中讀取字節流,再把它們反序列化成爲一個對象。
- java.io.ObjectOutputStream:對象輸出流
序列化、反序列化代碼示例
- 創建user對象:
public class User {
// transient、static 修飾的成員變量將不會被序列化
private transient String tag = null;
public String name;
public int id;
public User(String name, int id) {
this.name = name;
this.id = id;
}
}
- 對象序列化:
file = new File("D:\\student.txt");
User user = new User("張三", 22);
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(user);
oos.flush();
oos.close();
fos.close();
- 對象反序列化:
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
User user = (User) ois.readObject();
ois.close();
二、 Serializable
1、定義
Serializable 是Java用於標識可序列化定義的一個抽象空接口,對象實現了Serializable接口,標識該類可以被序列化、反序列化。Java 虛擬機會自動對該對象序列化、反系列化。
2、優勢與劣勢
1) 使用簡單,很方便將對象存儲到設備、網絡傳輸。
2)開銷很大,序列化、反序列化過程需要使用外部存儲器,有大量的I/O操作。
三、 Parcelable
推薦博文:探索Android中的Parcel機制
1、定義
Parcelable是Android中提供的序列化方式。
2、優勢與劣勢
1) 整個讀寫全是在內存中進行,效率高,性能開銷小。
2) android 官方推薦的序列化方式。
3) 使用稍微麻煩,需要自己寫序列化、反序列化的相應代碼。
4) 序列化內存中首選,序列化到存儲存儲、網絡傳輸實現複雜麻煩。
2、實現Parcelable步驟
1)implements Parcelable 接口
2)重寫writeToParcel方法,將你的對象序列化爲一個Parcel對象,即:將類的數據寫入外部提供的Parcel 容器中,將需要傳遞的數據到Parcel容器保存,以便從 Parcel容器獲取數據。
3)重寫describeContents方法,內容接口描述,默認返回0,如果有文件描述符返回1。
4)實例化靜態內部對象CREATOR實現接口Parcelable.Creator
public static final Parcelable.Creator CREATOR
注:其中public static final一個都不能少,內部對象CREATOR的名稱也不能改變,必須全部大寫。需重寫本接口中的兩個方法:createFromParcel(Parcel in) 實現從Parcel容器中讀取傳遞數據值,封裝成Parcelable對象返回邏輯層,newArray(int size) 創建一個類型爲T,長度爲size的數組,僅一句話即可(return new T[size]),供外部類反序列化本類數組使用。
簡而言之:通過writeToParcel將你的對象映射成Parcel對象,再通過createFromParcel將Parcel對象映射成你的對象。也可以將Parcel看成是一個流,通過writeToParcel把對象寫到流裏面,在通過createFromParcel從流裏讀取對象,只不過這個過程需要你來實現,因此寫的順序和讀的順序必須一致。
Serializable、與Parcelable 的使用場景。
1)在內存序列化上,使用Parcelable序列化方式。
2)在將對象序列化到存儲設備、網絡上傳輸使用Serializable序列化方式。
代碼實踐:
- Serializable
public class User implements Serializable {
public String name;
public int id;
public User(String name, int id) {
this.name = name;
this.id = id;
}
}
- Parcelable
public class User2 implements Parcelable {
public String name;
public int id;
public User2(String name, int id) {
this.name = name;
this.id = id;
}
/**
* 反序列話的過程
*/
public static final Creator<User2> CREATOR = new Creator<User2>() {
// 從序列化的對象中創建原始對象
@Override
public User2 createFromParcel(Parcel in) {
return new User2(in);
}
// 創建指定長度原始對象的數組
@Override
public User2[] newArray(int size) {
return new User2[size];
}
};
/**
* 返回當前對象的內容描述
*
* @return 0 不返回 (幾乎所有情況)、1 返回
*/
@Override
public int describeContents() {
return 0;
}
/**
* 對象序列化寫到 Parcel 容器中
*
* @param dest 容器
* @param flags 0 不返回(幾乎所有情況)、 1 表示當前對象需要作爲返回值返回,不能立即釋放資源
*/
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(id);
}
/**
* 對象反序列化 從Parcel 容器中讀取創建原始對象
*
* @param in 容器
*/
protected User2(Parcel in) {
name = in.readString();
id = in.readInt();
}
}
參考博客
https://www.cnblogs.com/renqingping/archive/2012/10/25/Parcelable.html