分享職場乾貨、軟體編程、程序人生和創業資源。
文|洪生鵬
程式設計師面試時,序列化知識點經常會遇到。
張工是一名java程式設計師,工作5年了,一直從事java開發。最近到某網際網路公司面試,做了筆試題後,有一道筆試題是這樣子的:Serializable有什麼作用,張工沒有作答,面談時面試官又問了,張工回答不出個所以然。面試官:你都工作五年了,連序列化都不知道,你這5年都幹些什麼了?張工一臉的無助,不過確實不應該,類似Serializable序列化這樣的知識點,平時應該不會少用。
小編之前參加的筆試也遇到了關於序列化的問題,關於序列化我們都能知道個大概,但要是能進一步分析個所以然那就更好了,這樣能給面試官留下更好的印象。
一般情況下,我們在定義實體類時會繼承Serializable接口,類似這樣:
我們在實體類中引用了Serializable這個接口,那麼這個接口到底有什麼?細心的你會發現我們還定義了個serialVersionUID變量。這個變量到底有什麼作用?
什麼是Serializable接口
一個對象序列化的接口,一個類只有實現了Serializable接口,它的對象才能被序列化。
什麼是序列化?
序列化是將對象狀態轉換為可保持或傳輸的格式的過程。與序列化相對的是反序列化,它將流轉換為對象。這兩個過程結合起來,可以輕鬆地存儲和傳輸數據。
為什麼要序列化對象
把對象轉換為字節序列的過程稱為對象的序列化把字節序列恢復為對象的過程稱為對象的反序列化什麼情況下需要序列化?
當我們需要把對象的狀態信息通過網絡進行傳輸,或者需要將對象的狀態信息持久化,以便將來使用時都需要把對象進行序列化
那為什麼還要繼承Serializable。那是存儲對象在存儲介質中,以便在下次使用的時候,可以很快捷的重建一個副本。
或許你會問,我在開發過程中,實體並沒有實現序列化,但我同樣可以將數據保存到mysql、Oracle資料庫中,為什麼非要序列化才能存儲呢?
我們來看看Serializable到底是什麼,跟進去看一下,我們發現Serializable接口裡面竟然什麼都沒有,只是個空接口
一個接口裡面什麼內容都沒有,我們可以將它理解成一個標識接口。
比如在課堂上有位學生遇到一個問題,於是舉手向老師請教,這時老師幫他解答,那麼這位學生的舉手其實就是一個標識,自己解決不了問題請教老師幫忙解決。在Java中的這個Serializable接口其實是給jvm看的,通知jvm,我不對這個類做序列化了,你(jvm)幫我序列化就好了。
Serializable接口就是Java提供用來進行高效率的異地共享實例對象的機制,實現這個接口即可。
什麼是JVM?
JVM是Java Virtual Machine(Java虛擬機)的縮寫,JVM是一種用於計算設備的規範,它是一個虛構出來的計算機,是通過在實際的計算機上仿真模擬各種計算機功能來實現的。
為什麼要定義serialversionUID變量
簡單看一下 Serializable接口的說明
從說明中我們可以看到,如果我們沒有自己聲明一個serialVersionUID變量,接口會默認生成一個serialVersionUID
However, it is <em>strongly recommended</em> that all serializable classes explicitly declare serialVersionUID values, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations, and can thus result in unexpected<code>InvalidClassException</code>s during deserialization.
但是強烈建議用戶自定義一個serialVersionUID,因為默認的serialVersinUID對於class的細節非常敏感,反序列化時可能會導致InvalidClassException這個異常。
在前面我們已經新建了一個實體類User實現Serializable接口,並且定義了serialVersionUID變量。
我們把User寫到文件,然後讀取出來。
是的,你沒有看錯,序列化與反序列化操作過程就是這麼的簡單。只需要將User寫入到文件中,然後再從文件中進行恢復,恢復後得到的內容與之前完全一樣,但是兩者是不同的對象。前面提到過一個問題,如果將serialVersionUID變量去掉,我們來看看,會發生什麼事情。
剛開始提到了,serialVersionUID要不要指定呢?如果不指定會出現什麼樣的後果?如果指定了以後後邊的值又代表著什麼意思呢?既然系統指定了這個欄位,那麼肯定是有它的作用的。
這個serialVersionUID是用來輔助對象的序列化與反序列化的,原則上序列化後的數據當中的serialVersionUID與當前類當中的serialVersionUID一致,那麼該對象才能被反序列化成功。這個serialVersionUID的詳細的工作機制是:在序列化的時候系統將serialVersionUID寫入到序列化的文件中去,當反序列化的時候系統會先去檢測文件中的serialVersionUID是否跟當前的文件的serialVersionUID是否一致,如果一直則反序列化成功,否則就說明當前類跟序列化後的類發生了變化,比如是成員變量的數量或者是類型發生了變化,那麼在反序列化時就會發生crash,並且回報出錯誤:
java.io.InvalidClassException: User; local class incompatible: stream classdesc serialVersionUID = -1451587475819212328, local class serialVersionUID = -3946714849072033140at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:699)at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1885)at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1751)at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2042)at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1573)at java.io.ObjectInputStream.readObject(ObjectInputStream.java:431)at Main.readUser(Main.java:32)at Main.main(Main.java:10)
小編認為,類似序列化這樣的基礎知識,平時在學習中要重視,才能編寫出更加高效穩定的程序。不知對此你是怎麼看待的,歡迎交流!