Java 的序列化機制是經過在運行時判斷類的serialVersionUID來驗證版本一致性的。在進行反序列化時,JVM會把傳來的字節流中的 serialVersionUID與本地相應實體(類)的serialVersionUID進行比較,若是相同就認爲是一致的,能夠進行反序列化,不然就 會出現序列化版本不一致的異常。
Eclipse中The serializable class XXXXXX does not declare a static final serialVersionUID field of type long出現這樣的警告處理辦法。
當採用程序的Add default Serial version ID修復時,Eclipse會加上:private static final long serialVersionUID = 1L;
當採用程序的Add generated Serial version ID修復時,Eclipse會加上:private static final long serialVersionUID = xxxxL;
其實這個問題出現的具體緣由是和序列化中的這個serialVersionUID有關。
serialVersionUID 用來代表類的不一樣版本間的兼容性。有兩種生成方式:
一個是默認的1L,好比:private static final long serialVersionUID = 1L;(對應修復方法1)
一個是根據類名、接口名、成員方法及屬性等來生成一個64位的哈希字段,好比:
private static final long serialVersionUID = xxxxL;(對應修復方法2)
在JDK中,能夠利用JDK的bin目錄下的serialver.exe工具產生這個serialVersionUID 的值,對於Test.class,執行命令:
serialver Test 這時JVM(java虛擬機)會生成一個哈希字段。
對比一下這個哈希字段的值與方法2中生成的字段值是同樣的,可見,在CMD中使用serialver指令就是根據類名、接口名、成員方法及屬性等來生成哈希字段的。
下面來討論java類中爲何須要重載 serialVersionUID 屬性。
當兩個進程在進行遠程通訊時,彼此能夠發送各類類型的數據。不管是何種類型的數據,都會以二進制序列的形式在網絡上傳送。發送方須要把這個Java對象轉換爲字節序列,才能在網絡上傳送;接收方則須要把字節序列再恢復爲Java對象。
把Java對象轉換爲字節序列的過程稱爲對象的序列化。
把字節序列恢復爲Java對象的過程稱爲對象的反序列化。
對象的序列化主要有兩種用途:
1) 把對象的字節序列永久地保存到硬盤上,一般存放在一個文件中;
2) 在網絡上傳送對象的字節序列。
java.io.ObjectOutputStream表明對象輸出流,它的writeObject(Object obj)方法可對參數指定的obj對象進行序列化,把獲得的字節序列寫到一個目標輸出流中。
java.io.ObjectInputStream表明對象輸入流,它的readObject()方法從一個源輸入流中讀取字節序列,再把它們反序列化爲一個對象,並將其返回。
只有實現了Serializable和Externalizable接口的類的對象才能被序列化。Externalizable接口繼承自 Serializable接口,實現Externalizable接口的類徹底由自身來控制序列化的行爲,而僅實現Serializable接口的類能夠 採用默認的序列化方式 。
凡是實現Serializable接口的類都有一個表示序列化版本標識符的靜態變量:private static final long serialVersionUID;
類的serialVersionUID的默認值徹底依賴於Java編譯器的實現,對於同一個類,用不一樣的Java編譯器編譯,有可能會致使不一樣的 serialVersionUID,也有可能相同。爲了提升serialVersionUID的獨立性和肯定性,強烈建議在一個可序列化類中顯示的定義 serialVersionUID,爲它賦予明確的值。顯式地定義serialVersionUID有兩種用途:
1)在某些場合,但願類的不一樣版本對序列化兼容,所以須要確保類的不一樣版本具備相同的serialVersionUID;在某些場合,不但願類的不一樣版本對序列化兼容,所以須要確保類的不一樣版本具備不一樣的serialVersionUID。
2)當你序列化了一個類實例後,但願更改一個字段或添加一個字段,不設置serialVersionUID,所作的任何更改都將致使沒法反序化舊有實 例,並在反序列化時拋出一個異常。若是你添加了serialVersionUID,在反序列舊有實例時,新添加或更改的字段值將設爲初始化值(對象爲 null,基本類型爲相應的初始默認值),字段被刪除將不設置。
當系統不須要序列化類時,能夠去掉這些警告,作以下設置:Window-->Preferences-->Java,將 serializable class without serialVersionUID的設置由warning改成Ignore。而後Eclipse會從新編譯程序,那些警告信息也就消失了。
struts架構下的網站常常出現javax.servlet.ServletException: BeanUtils.populate 錯誤,可是本地運行又一切正常,惟一以爲可能產生問題的就是服務器上跑了好幾個網站,都是同樣的架構的,懷疑是否是web容器把幾個項目之間的java類 給共用了,考慮到不少類都定義了serialVersionUID字段,而後嘗試刪除了某個類的serialVersionUID,結果關於該類的操做就 恢復正常了。網上簡單查閱了一下資料,感受是tomcat把全部類串行化時候,因爲咱們的幾個項目不少java類都是複製粘貼的,因此致使了不少類的 serialVersionUID都是同一個值,因此tomcat會把不一樣項目的相同類名的類看成同一個類去處理,致使了這個奇怪的錯誤。
解決方案:
每一個項目同名的類serialVersionUID改成不同,不能直接的複製粘貼過來。java