一、概念:
1、序列化
將數(shù)據(jù)結(jié)構(gòu)或?qū)ο筠D(zhuǎn)換成二進(jìn)制串的過程。
2、反序列化
將在序列化過程中所生成的二進(jìn)制串轉(zhuǎn)換成數(shù)據(jù)結(jié)構(gòu)或者對(duì)象的過程。
3、Serializable接口
是 Java 提供的序列化接口,它是一個(gè)空接口:
public interface Serializable {}
Serializable 用來標(biāo)識(shí)當(dāng)前類可以被 ObjectOutputStream 序列化,以及被 ObjectInputStream 反序列化。
Serializable 有以下幾個(gè)特點(diǎn):
- 可序列化類中,未實(shí)現(xiàn) Serializable 的屬性狀態(tài)無法被序列化/反序列化;
- 也就是說,反序列化一個(gè)類的過程中,它的非可序列化的屬性將會(huì)調(diào)用無參構(gòu)造函數(shù)重新創(chuàng)建;
- 因此這個(gè)屬性的無參構(gòu)造函數(shù)必須可以訪問,否者運(yùn)行時(shí)會(huì)報(bào)錯(cuò);
- 一個(gè)實(shí)現(xiàn)序列化的類,它的子類也是可序列化的;
4、Binder


5、Parcelabel 與Serializable的區(qū)別

二、面試:
1、反序列化后的對(duì)象會(huì)重新調(diào)用構(gòu)造函數(shù)嗎?
答:不會(huì), 因?yàn)槭菑亩M(jìn)制直接解析出來的. 適用的是 Object 進(jìn)行接收再強(qiáng)轉(zhuǎn), 因此不是原來的那個(gè)對(duì)象
2、序列化與反序列化后的對(duì)象是什么關(guān)系,是("=="還是equal?是淺復(fù)制還是深復(fù)制?)?
答:是一個(gè)深拷貝, 前后對(duì)象的引用地址不同
3、Android 為什么要設(shè)計(jì) bundle 而不是使用 HashMap 結(jié)構(gòu)?
答:bundle 內(nèi)部適用的是 ArrayMap, ArrayMap 相比 Hashmap 的優(yōu)點(diǎn)是, 擴(kuò)容方便, 每次擴(kuò)容是原容量的一半, 在[百量] 級(jí)別, 通過二分法查找 key 和 value (ArrayMap 有兩個(gè)數(shù)組, 一個(gè)存放 key 的 hashcode, 一個(gè)存放 key+value 的 Entry) 的效率要比 hashmap 快很多, 由于在內(nèi)存中或者 Android 內(nèi)部傳輸中一般數(shù)據(jù)量較小, 因此用 bundle 更為合適
4、serializableVersionUID 的作用是?
用于數(shù)據(jù)的版本控制, 如果反序列化后發(fā)現(xiàn) ID 不一樣, 認(rèn)為不是之前序列化的對(duì)象
5、Android 中 intent/bundle 的通信原理以及大小限制?
答: Android 中的 bundle 實(shí)現(xiàn)了 parcelable 的序列化接口, 目的是為了在進(jìn)程間進(jìn)行通訊, 不同的進(jìn)程共享一片固定大 小的內(nèi)存, parcelable 利用 parcel 對(duì)象的 read/write 方法, 對(duì)需要傳遞的數(shù)據(jù)進(jìn)行內(nèi)存讀寫, 因此這一塊共享內(nèi)存不能 過大, 在利用 bundle 進(jìn)行傳輸時(shí), 會(huì)初始化一個(gè) BINDER_VM_SIZE 的大小 = 1 * 1024 * 1024 - 4096 * 2, 即便通過 修改 Framework 的代碼, bundle 內(nèi)核的映射只有 4M, 最大只能擴(kuò)展到 4M.
6、為何 Intent 不能直接在組件間傳遞對(duì)象而要通過序列化機(jī)制?
答: 因?yàn)?Activity 啟動(dòng)過程是需要與 AMS 交互, AMS 與 UI 進(jìn)程是不同一個(gè)的, 因此進(jìn)程間需要交互數(shù)據(jù), 就必須序列化。
7、序列化與持久化的關(guān)系和區(qū)別?
答: 序列化是為了進(jìn)程間數(shù)據(jù)交互而設(shè)計(jì)的, 持久化是為了把數(shù)據(jù)存儲(chǔ)下來而設(shè)計(jì)的
8、什么是 serialVersionUID ?如果你不定義這個(gè), 會(huì)發(fā)生什么?
假設(shè)你有一個(gè)類,它序列化并存儲(chǔ)在持久性中, 然后修改了該類以添加新字 段。如果對(duì)已序列化的對(duì)象進(jìn)行反序列化, 會(huì)發(fā)生什么情況?
serialVersionUID 是一個(gè) private static final long 型 ID, 當(dāng)它被印在對(duì)象上時(shí), 它通常是
對(duì)象的哈希碼,你可以使用 serialver 這個(gè) JDK 工具來查看序列化對(duì)象的 serialVersionUID。
SerialVerionUID 用于對(duì)象的版本控制。也可以在類文件中指定 serialVersionUID。不指定
serialVersionUID的后果是,當(dāng)你添加或修改類中的任何字段時(shí), 則已序列化類將無法恢復(fù), 因?yàn)?br>
為新類和舊序列化對(duì)象生成的 serialVersionUID 將有所不同。Java 序列化過程依賴于正確的序
列化對(duì)象恢復(fù)狀態(tài)的, ,并在序列化對(duì)象序列版本不匹配的情況下引發(fā)

9、序列化時(shí),你希望某些成員不要序列化?你如何實(shí)現(xiàn)它?
有時(shí)候也會(huì)變著形式問,比如問什么是瞬態(tài) trasient 變量, 瞬態(tài)和靜態(tài)變量會(huì)不會(huì)得到序列化等,所以,如果你不希望任何字段是對(duì)象的狀態(tài)的一部分, 然后聲明它靜態(tài)或瞬態(tài)根據(jù)你的需要, 這樣就不會(huì)是在 Java 序列化過程中被包含在內(nèi)
10、如果類中的一個(gè)成員未實(shí)現(xiàn)可序列化接口, 會(huì)發(fā)生什么情況?
如果嘗試序列化實(shí)現(xiàn)可序列化的類的對(duì)象,但該對(duì)象包含對(duì)不可序列化類的引用,則在運(yùn)行時(shí)將引發(fā)不可序列化異常 NotSerializableException.
11、如果類是可序列化的, 但其超類不是, 則反序列化后從超級(jí)類繼承的實(shí)例
變量的狀態(tài)如何?
Java 序列化過程僅在對(duì)象層次都是可序列化結(jié)構(gòu)中繼續(xù), 即實(shí)現(xiàn) Java 中的可序列化接口, 并且
從超級(jí)類繼承的實(shí)例變量的值將通過調(diào)用構(gòu)造函數(shù)初始化, 在反序列化過程中不可序列化的超級(jí)類
12、是否可以自定義序列化過程, 或者是否可以覆蓋 Java 中的默認(rèn)序列化過
程?
是的,Java 中的序列化過程是可以自定義的,可以通過實(shí)現(xiàn) java.io.Serializable 接口的 writeObject 和 readObject 方法來完成自定義序列化和反序列化過程。這樣可以覆蓋默認(rèn)的序列化過程,實(shí)現(xiàn)更靈活的序列化和反序列化操作。
13、假設(shè)新類的超級(jí)類實(shí)現(xiàn)可序列化接口, 如何避免新類被序列化?
對(duì)于序列化一個(gè)對(duì)象需調(diào)用 ObjectOutputStream.writeObject(saveThisObject), 并用
ObjectInputStream.readObject() 讀取對(duì)象, 但 Java 虛擬機(jī)為你提供的還有一件事, 是定義這
兩個(gè)方法。如果在類中定義這兩種方法, 則 JVM 將調(diào)用這兩種方法, 而不是應(yīng)用默認(rèn)序列化機(jī)制。你可以在此處通過執(zhí)行任何類型的預(yù)處理或后處理任務(wù)來自定義對(duì)象序列化和反序列化的行為。
14、在 Java 中的序列化和反序列化過程中使用哪些方法?
Java 中的序列化和反序列化過程中,常用的方法有以下幾個(gè):
1、java.io.Serializable 接口
Java 中的序列化和反序列化操作需要使用
java.io.Serializable接口,該接口沒有任何方法,只是用于標(biāo)記一個(gè)類可以被序列化。如果一個(gè)類實(shí)現(xiàn)了Serializable接口,則可以將該類的對(duì)象序列化和反序列化。
2、java.io.ObjectOutputStream 和 java.io.ObjectInputStream 類java.io.ObjectOutputStream 和 java.io.ObjectInputStream 類是 Java 中用于序列化和反序列化的核心類,它們提供了一些方法來實(shí)現(xiàn)對(duì)象的序列化和反序列化。
比如:
-
ObjectOutputStream.writeObject(Object obj):將一個(gè)對(duì)象寫入序列化流中。 -
ObjectInputStream.readObject():從序列化流中讀取一個(gè)對(duì)象。java.io.Externalizable 接口
3、java.io.Externalizable接口也可以用于自定義序列化和反序列化過程,
它提供了兩個(gè)方法:
writeExternal和readExternal,用于自定義序列化和反序列化過程。與 Serializable 接口不同的是,實(shí)現(xiàn)Externalizable 接口的類需要顯式地定義無參構(gòu)造函數(shù)。
總的來說,Java 中的序列化和反序列化過程是通過實(shí)現(xiàn) Serializable 接口并使用 ObjectOutputStream 和 ObjectInputStream 類來實(shí)現(xiàn)的。如果需要自定義序列化和反序列化過程,則可以實(shí)現(xiàn) Externalizable 接口并重新定義 writeExternal 和 readExternal 方法。