不少商業項目用到數據庫、內存映射文件和普通文件來完成項目中的序列化處理的需求,可是這些方法不多會依靠於Java序列化。本文也不是用來解釋序列化的,而是一塊兒來看看面試中有關序列化的問題,這些問題你頗有可能不瞭解。「Java序列化指的是將對象轉換程字節格式並將對象狀態保存在文件中,一般是.ser擴展名的文件。而後能夠經過.ser文件從新建立Java對象,這個過程爲返序列化」java
Java序列化的API中提供了開發人員進行序列化對象的機制,經過Serializable和Externalizable接口。面試
一塊兒看看這些問題:
1)Java中的Serializable接口和Externalizable接口有什麼區別?算法
這個是面試中關於Java序列化問的最多的問題。個人回答是,Externalizable接口提供了兩個方法writeExternal()和readExternal()。這兩個方法給咱們提供了靈活處理Java序列化的方法,經過實現這個接口中的兩個方法進行對象序列化能夠替代Java中默認的序列化方法。正確的實現Externalizable接口能夠大幅度的提升應用程序的性能。數據庫
2)Serializable接口中有借個方法?若是沒有方法的話,那麼這麼設計Serializable接口的目的是什麼?編程
Serializable接口在java.lang包中,是Java序列化機制的核心組成部分。它裏面沒有包含任何方法,咱們稱這樣的接口爲標識接口。若是你的類實現了Serializable接口,這意味着你的類被打上了「能夠進行序列化」的標籤,而且也給了編譯器指示,可使用序列化機制對這個對象進行序列化處理。app
3)什麼是serialVersionUID?若是你沒有定義serialVersionUID意味着什麼?ide
SerialVersionUID應該是你的類中的一個public static final類型的常量,若是你的類中沒有定義的話,那麼編譯器將拋出警告。若是你的類中沒有制定serialVersionUID,那麼Java編譯器會根據類的成員變量和必定的算法生成用來表達對象的serialVersionUID ,一般是用來表示類的哈希值(hash code)。結論是,若是你的類沒有實現SerialVersionUID,那麼若是你的類中若是加入或者改變成員變量,那麼已經序列化的對象將沒法反序列化。這是覺得,類的成員變量的改變意味這編譯器生成的SerialVersionUID的值不一樣。Java序列化過程是經過正確SerialVersionUID來對已經序列化的對象進行狀態恢復。函數
4)當對象進行序列化的時候,若是你不但願你的成員變量進行序列化,你怎麼辦?性能
這個問題也會這麼問,如何使用暫態類型的成員變量?暫態和靜態成員變量是否會被序列化等等。若是你不但願你的對象中的成員變量的狀態得以保存,你能夠根據需求選擇transient或者static類型的變量,這樣的變量不參與Java序列化處理的過程。設計
5)若是一個類中的成員變量是其它符合類型的Java類,而這個類沒有實現Serializable接口,那麼當對象序列化的時候會怎樣?
若是你的一個對象進行序列化,而這個對象中包含另一個引用類型的成員編程,而這個引用的類沒有實現Serializable接口,那麼當對象進行序列化的時候會拋出「NotSerializableException「的運行時異常。
6)若是一個類是可序列化的,而他的超類沒有,那麼當進行反序列化的時候,那些從超類繼承的實例變量的值是什麼?
Java中的序列化處理實例變量只會在全部實現了Serializable接口的繼承支路上展開。因此當一個類進行反序列化處理的時候,超類沒有實現Serializable接口,那麼從超類繼承的實例變量會經過爲實現序列化接口的超類的構造函數進行初始化。
7) Can you Customize Serialization process or can you override default Serialization process in Java?
7)你可以自定義序列化處理的代碼嗎或者你能重載Java中默認的序列化方法嗎?
答案是確定的,能夠。咱們都知道能夠經過ObjectOutputStream中的writeObject()方法寫入序列化對象,經過ObjectInputStream中的readObject()讀入反序列化的對象。這些都是Java虛擬機提供給你的兩個方法。若是你在你的類中定義了這兩個方法,那麼JVM就會用你的方法代替原有默認的序列化機制的方法。你能夠經過這樣的方式類自定義序列化和反序列化的行爲。須要注意的一點是,最好將這兩個方法定義爲private,以防止他們被繼承、重寫和重載。也只有JVM能夠訪問到你的類中全部的私有方法,你不用擔憂方法私有不會被調用到,Java序列化過程會正常工做。
8)假設一個新的類的超類實現了Serializable接口,那麼如何讓這個新的子類不被序列化?
若是一個超類已經序列化了,那麼沒法經過是否實現什麼接口的方式再避免序列化的過程了,可是也還有一種方式可使用。那就是須要你在你的類中從新實現writeObject()和readObject()方法,並在方法實現中經過拋出NotSerializableException。
9)在Java進行序列化和反序列化處理的時候,哪些方法被使用了?
這個是面試中常見的問題,主要用來考察你是否對readObject()、writeObject()、readExternal()和writeExternal()方法的使用熟悉。Java序列化是經過java.io.ObjectOutputStream這個類來完成的。這個類是一個過濾器流,這個類完成對底層字節流的包裝來進行序列化處理。咱們經過ObjectOutputStream.writeObject(obj)進行序列化,經過ObjectInputStream.readObject()進行反序列化。對writeObject()方法的調用會觸發Java中的序列化機制。readObject()方法用來將已經持久化的字節數據反向建立Java對象,該方法返回Object類型,須要強制轉換成你須要的正確類型。
10) Suppose you have a class which you serialized it and stored in persistence and later modified that class to add a new field. What will happen if you deserialize the object already serialized?
10)假設你有一個類而且已經將這個類的某一個對象序列化存儲了,那麼若是你在這個類中加入了新的成員變量,那麼在反序列化剛纔那個已經存在的對象的時候會怎麼樣?
這個取決於這個類是否有serialVersionUID成員。經過上面的,咱們已經知道若是你的類沒有提供serialVersionUID,那麼編譯器會自動生成,而這個serialVersionUID就是對象的hash code值。那麼若是加入新的成員變量,從新生成的serialVersionUID將和以前的不一樣,那麼在進行反序列化的時候就會產生java.io.InvalidClassException的異常。這就是爲何要建議爲你的代碼加入serialVersionUID的緣由所在了。