JAVA的序列化機制serialVersionUID的作用

Java的序列化機制是通過在運行時判斷類的serialVersionUID來驗證版本一致性的。在進行反序列化時,JVM會把傳來的字節流中的serialVersionUID與本地相應實體(類)的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改爲不一樣,不能直接的複製粘貼過來。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章