Java類經過實現 java.io.Serializable 接口以啓用其序列化功能。未實現此接口的類將沒法進行序列化或反序列化。可序列化類的全部子類型自己都是可序列化的。java
若是讀者看過Serializable的源碼,就會發現,他只是一個空的接口,裏面什麼東西都沒有。Serializable接口沒有方法或字段,僅用於標識可序列化的語義。可是,若是一個類沒有實現這個接口,想要被序列化的話,就會拋出java.io.NotSerializableException異常。eclipse
序列號在寫成二進制流的時候,會調用以下的方法:code
Externalizable繼承自Serializable,該接口中定義了兩個抽象方法:writeExternal()與readExternal()。對象
當使用Externalizable接口來進行序列化與反序列化的時候須要開發人員重寫writeExternal()與readExternal()方法。不然全部變量的值都會變成默認值。blog
transient 關鍵字的做用是控制變量的序列化,在變量聲明前加上該關鍵字,能夠阻止該變量被序列化到文件中,在被反序列化後,transient 變量的值被設爲初始值,如 int 型的是 0,對象型的是 null。繼承
序列化是將對象的狀態信息轉換爲可存儲或傳輸的形式的過程。咱們都知道,Java對象是保存在JVM的堆內存中的,也就是說,若是JVM堆不存在了,那麼對象也就跟着消失了。接口
而序列化提供了一種方案,可讓你在即便JVM停機的狀況下也能把對象保存下來的方案。就像咱們平時用的U盤同樣。把Java對象序列化成可存儲或傳輸的形式(如二進制流),好比保存在文件中。這樣,當再次須要這個對象的時候,從文件中讀取出二進制流,再從二進制流中反序列化出對象。ip
虛擬機是否容許反序列化,不只取決於類路徑和功能代碼是否一致,一個很是重要的一點是兩個類的序列化 ID 是否一致,這個所謂的序列化ID,就是咱們在代碼中定義的serialVersionUID。內存
這是由於,在進行反序列化時,JVM會把傳來的字節流中的serialVersionUID與本地相應實體類的serialVersionUID進行比較,若是相同就認爲是一致的,能夠進行反序列化,不然就會出現序列化版本不一致的異常,便是InvalidCastException。開發
若是咱們沒有在類中明確的定義一個serialVersionUID的話,看看會發生什麼。
嘗試修改上面的demo代碼,先使用如下類定義一個對象,該類中不定義serialVersionUID,將其寫入文件。
而後咱們修改User1類,向其中增長一個屬性。在嘗試將其從文件中讀取出來,並進行反序列化。
執行結果:
java.io.InvalidClassException: com.hollis.User1; local class incompatible: stream classdesc serialVersionUID = -2986778152837257883, local class serialVersionUID = 7961728318907695402
一樣,拋出了InvalidClassException,而且指出兩個serialVersionUID不一樣,分別是-2986778152837257883和7961728318907695402。
從這裏能夠看出,系統本身添加了一個serialVersionUID。
因此,一旦類實現了Serializable,就建議明確的定義一個serialVersionUID。否則在修改類的時候,就會發生異常。
serialVersionUID有兩種顯示的生成方式:
一種是默認的1L,好比:
private static final long serialVersionUID = 1L;
另一種是根據類名、接口名、成員方法及屬性等來生成一個64位的哈希字段,好比:
private static final long serialVersionUID = xxxxL;
後面這種方式,能夠藉助IDE生成,後面會介紹。
爲了簡化代碼量,反序列化的調用鏈以下:
在initNonProxy中 ,關鍵代碼以下:
在反序列化過程當中,對serialVersionUID作了比較,若是發現不相等,則直接拋出異常。
深刻看一下getSerialVersionUID方法:
在沒有定義serialVersionUID的時候,會調用computeDefaultSUID 方法,生成一個默認的serialVersionUID。
這也就找到了以上兩個問題的根源,實際上是代碼中作了嚴格的校驗,而且在未定義的時候自動生成了一個serialVersionUID。
爲了確保咱們不會忘記定義serialVersionUID,能夠調節一下Intellij IDEA的配置,在實現Serializable接口後,若是沒定義serialVersionUID的話,IDEA(eclipse同樣)會進行提示:
而且能夠一鍵生成一個:
固然,這個配置並非默認生效的,須要手動到IDEA中設置一下:
在圖中標號3的地方(Serializable class without serialVersionUID的配置),打上勾,保存便可。