一 概念
- 序列化:將數(shù)據(jù)結(jié)構(gòu)或?qū)ο筠D(zhuǎn)換成二進制串的過程。
- 反序列化:將在序列化過程中所生成的二進制串轉(zhuǎn)換成數(shù)據(jù)結(jié)構(gòu)或者對象的過程
序列化方案
- Serializable
注意:
1.必須要有無參構(gòu)造函數(shù)
2.Serializable接口可以自定義序列化邏輯
private void writeObject(ObjectOutputStream out)
private void readObject(ObjectInputStream in)
3.自定義序列化邏輯必須一一對應
4.反序列化對象不是通過自身無參構(gòu)造函數(shù)梯码,而是通過父類即Object生成
/* @author unascribed
* @see java.io.ObjectOutputStream
* @see java.io.ObjectInputStream
* @see java.io.ObjectOutput
* @see java.io.ObjectInput
* @see java.io.Externalizable
* @since JDK1.1
*/
public interface Serializable {
}
##########Externalizable############
public interface Externalizable extends java.io.Serializable {
void writeExternal(ObjectOutput out) throws IOException;
void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
}
- json睹逃、xml
- Parcelable
serialVersionUID
serialVersionUID 是一個 private static final long 型 ID, 當它被印在對象上時, 它通常是 對象的哈希碼,你可以使用 serialver 這個 JDK 工具來查看序列化對象的 serialVersionUID硅急。 SerialVerionUID 用于對象的版本控制芳撒。也可以在類文件中指定 serialVersionUID禀梳。不指定 serialVersionUID的后果是,當你添加或修改類中的任何字段時, 則已序列化類將無法恢復, 因為 為新類和舊序列化對象生成的 serialVersionUID 將有所不同覆致。Java 序列化過程依賴于正確的序 列化對象恢復狀態(tài)的, ,并在序列化對象序列版本不匹配的情況下引發(fā)InvalidClassException
java.io.InvalidClassException: com.example.xuliehuademo01.demo01$User1; local class incompatible: stream classdesc serialVersionUID = 2, local class serialVersionUID = 3
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:699)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:2001)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1848)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2158)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1665)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:501)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:459)
序列化時,你希望某些成員不要序列化
瞬態(tài) trasient 變量, 瞬態(tài)和靜態(tài)變量會不會得到序列化等, 所以,如果你不希望任何字段是對象的狀態(tài)的一部分, 然后聲明它靜態(tài)或瞬態(tài)根據(jù)你的需要, 這樣 就不會是在 Java 序列化過程中被包含在內(nèi)
private static ObjectStreamField[] getDefaultSerialFields(Class<?> cl) {
Field[] clFields = cl.getDeclaredFields();
ArrayList<ObjectStreamField> list = new ArrayList<>();
int mask = Modifier.STATIC | Modifier.TRANSIENT;//NOTICE
for (int i = 0; i < clFields.length; i++) {
if ((clFields[i].getModifiers() & mask) == 0) {
list.add(new ObjectStreamField(clFields[i], false, true));
}
}
int size = list.size();
return (size == 0) ? NO_FIELDS :
list.toArray(new ObjectStreamField[size]);
}
如果類中的一個成員未實現(xiàn)可序列化接口
如果嘗試序列化實現(xiàn)可序列化的類的對象,但該對象包含對不可序列化類的引用,則在運行時將引發(fā) 不可序列化異常 NotSerializableException
如果類是可序列化的, 但其超類不是, 則反序列化后從超級類繼承的實例 變量的狀態(tài)如何
Java 序列化過程僅在對象層次都是可序列化結(jié)構(gòu)中繼續(xù), 即實現(xiàn) Java 中的可序列化接口, 并且 從超級類繼承的實例變量的值將通過調(diào)用構(gòu)造函數(shù)初始化, 在反序列化過程中不可序列化的超級類
是否可以自定義序列化過程, 或者是否可以覆蓋 Java 中的默認序列化過程
對于序列化一個對象需調(diào)用 ObjectOutputStream.writeObject(saveThisObject), 并用 ObjectInputStream.readObject() 讀取對象, 但 Java 虛擬機為你提供的還有一件事, 是定義這 兩個方法愈涩。如果在類中定義這兩種方法, 則 JVM 將調(diào)用這兩種方法, 而不是應用默認序列化機制望抽。 你可以在此處通過執(zhí)行任何類型的預處理或后處理任務來自定義對象序列化和反序列化的行為。
在 Java 中的序列化和反序列化過程中使用哪些方法
考熟悉 readObject() 的用法钠署、writeObject()糠聪、readExternal() 和 writeExternal()。 Java 序列化由java.io.ObjectOutputStream類完成谐鼎。該類是一個篩選器流, 它封裝在較低級別的 字節(jié)流中, 以處理序列化機制舰蟆。要通過序列化機制存儲任何對象, 我們調(diào)用 ObjectOutputStream.writeObject(savethisobject), 并反序列化該對象, 我們稱之為 ObjectInputStream.readObject()方法。調(diào)用以 writeObject() 方法在 java 中觸發(fā)序列化過程狸棍。 關于 readObject() 方法, 需要注意的一點很重要一點是, 它用于從持久性讀取字節(jié), 并從這些字 節(jié)創(chuàng)建對象, 并返回一個對象, 該對象需要類型強制轉(zhuǎn)換為正確的類型
反序列化后的對象會重新調(diào)用構(gòu)造函數(shù)嗎?
不會, 因為是從二進制直接解析出來的. 使用的是 Object 進行接收再強轉(zhuǎn), 因此不是原來的那個對象
序列化與反序列化后的對象是什么關系?
是一個深拷貝, 前后對象的引用地址不同
Android 為什么要設計 bundle 而不是使用 HashMap 結(jié)構(gòu)?
bundle 內(nèi)部適用的是 ArrayMap, ArrayMap 相比 Hashmap 的優(yōu)點是, 擴容方便, 每次擴容是原容量的一半, 在[百量] 級別, 通過二分法查找 key 和 value (ArrayMap 有兩個數(shù)組, 一個存放 key 的 hashcode, 一個存放 key+value 的 Entry) 的效率要比 hashmap 快很多, 由于在內(nèi)存中或者 Android 內(nèi)部傳輸中一般數(shù)據(jù)量較小, 因此用 bundle 更為合適
serializableVersionUID 的作用是?
用于數(shù)據(jù)的版本控制, 如果反序列化后發(fā)現(xiàn) ID 不一樣, 認為不是之前序列化的對象
Android 中 intent/bundle 的通信原理以及大小限制?
Android 中的 bundle 實現(xiàn)了 parcelable 的序列化接口, 目的是為了在進程間進行通訊, 不同的進程共享一片固定大小的內(nèi)存, parcelable 利用 parcel 對象的 read/write 方法, 對需要傳遞的數(shù)據(jù)進行內(nèi)存讀寫, 因此這一塊共享內(nèi)存不能過大, 在利用 bundle 進行傳輸時, 會初始化一個 BINDER_VM_SIZE 的大小 = 1 * 1024 * 1024 - 4096 * 2, 即便通過修改 Framework 的代碼, bundle 內(nèi)核的映射只有 4M, 最大只能擴展到 4M.
為何 Intent 不能直接在組件間傳遞對象而要通過序列化機制?
因為 Activity 啟動過程是需要與 AMS 交互, AMS 與 UI 進程是不同一個的, 因此進程間需要交互數(shù)據(jù), 就必須序列化
序列化與持久化的關系和區(qū)別?
序列化是為了進程間數(shù)據(jù)交互而設計的, 持久化是為了把數(shù)據(jù)存儲下來而設計的