Android數(shù)據(jù)序列化與反序列化

一、概念:

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

e0b16692aec8aa7d32835068bda93e6.png
9fe4e9af2e59dbe6b493a5985019197.png

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

72fbf4f1e11383a60306a6ee008a44b.png

二、面試:

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ā)

image.png

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.ObjectOutputStreamjava.io.ObjectInputStreamjava.io.ObjectOutputStreamjava.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è)方法:
    writeExternalreadExternal,用于自定義序列化和反序列化過程。與 Serializable 接口不同的是,實(shí)現(xiàn) Externalizable 接口的類需要顯式地定義無參構(gòu)造函數(shù)。

總的來說,Java 中的序列化和反序列化過程是通過實(shí)現(xiàn) Serializable 接口并使用 ObjectOutputStreamObjectInputStream 類來實(shí)現(xiàn)的。如果需要自定義序列化和反序列化過程,則可以實(shí)現(xiàn) Externalizable 接口并重新定義 writeExternalreadExternal 方法。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、概述 對(duì)象序列化的意思就是將對(duì)象的狀態(tài)轉(zhuǎn)換成字節(jié)流,以后可以通過這些值在生成相同狀態(tài)的對(duì)象,對(duì)象序列化就是對(duì)象...
    mumuxi_閱讀 1,339評(píng)論 0 2
  • 一、前言 對(duì)于Android開發(fā)者來說,IPC機(jī)制肯定不陌生,而作為Android的進(jìn)階也必須掌握IPC機(jī)制。所謂...
    丶藍(lán)天白云夢(mèng)閱讀 3,878評(píng)論 14 18
  • 在Java中,我們可以通過多種方式來創(chuàng)建對(duì)象,并且只要對(duì)象沒有被回收我們都可以復(fù)用該對(duì)象。但是,我們創(chuàng)建出來的這些...
    懶癌正患者閱讀 1,672評(píng)論 0 12
  • 官方文檔理解 要使類的成員變量可以序列化和反序列化,必須實(shí)現(xiàn)Serializable接口。任何可序列化類的子類都是...
    獅_子歌歌閱讀 2,554評(píng)論 1 3
  • 公眾號(hào):追風(fēng)棧Binary 我們通過文本或者數(shù)據(jù)庫的方式來永久化存儲(chǔ)程序中產(chǎn)生的數(shù)據(jù)。這種思路也可以借鑒到保存Ja...
    windytouch閱讀 550評(píng)論 0 1

友情鏈接更多精彩內(nèi)容