关于serialVersionUID的说明
1、為什么要使用serialVersionUID
(1)對于實現(xiàn)了Serializable接口的類,可以將其序列化輸出至磁盤文件中,同時會將其serialVersionUID輸出到文件中。
(2)然后有需要使用時,再從磁盤將對象內容及serialVersionUID讀入內容中的某個對象。
(3)將磁盤內容讀入對象時,需要進行強制類型轉換,如Person person = (Person)ois.readObject();?
(4) 此時,將對比從磁盤讀入的Serializable與對象所屬類(如Person)的Serializable,若二者一致,則轉換成功。若二者不一致,則轉換失敗,并拋出InvalidClassException。
如果沒有為類指定serialVersionUID,則JVM會自動根據(jù)類的內容生成一個serialVersionUID,類中的任何變化均會導致serialVersionUID的變化,如新增一個空格。
因此,若一個類沒有指定serialVersionUID,而且發(fā)生了變化,則讀取磁盤中的對象時就會報錯。
2、何時應該修改serialVersionUID
若對象已經(jīng)修改較多或者修改成不兼容的模式,導致原來輸出到磁盤的內容不應再轉換至原對象,此時則應該修改serialVersionUID。
When should update your serialVersionUID?
When your serialization class is updated with some incompatible Java type changes to a serializable class, you have to update your serialVersionUID.
3、如何創(chuàng)建serialVersionUID
以下內容參考:http://zengxiankang2011.blog.163.com/blog/static/1783603192011594938588/?fromdm&isFromSearchEngine=yes
在Eclipse中,提供兩種方式讓我們快速添加SerialVersionUid。
add default serial version ID:
Adds a default serial version ID to the selected type
Use this option to add a user-defined ID in combination with custom serialization code if the type did undergo structural change since its first release.
add generated serial version ID:
Adds a generated serial version ID to the selected type
Use this option to add a compiler-generated ID if the type didnot undergo structural change since its first release.
一種就是1L,一種是生成一個很大的數(shù),這兩種有什么區(qū)別呢?
看上去,好像每個類的這個類不同,似乎這個SerialVersionUid在類之間有某種關聯(lián)。其實不然,兩種都可以,從JDK文檔也看不出這一點。我們只要保證在同一個類中,不同版本根據(jù)兼容需要,是否更改SerialVersionUid即可。
對于第一種,需要了解哪些情況是可兼容的,哪些根本就不兼容。 參考文檔:http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf
在可兼容的前提下,可以保留舊版本號,如果不兼容,或者想讓它不兼容,就手工遞增版本號。
1->2->3.....
第二種方式,是根據(jù)類的結構產(chǎn)生的hash值。增減一個屬性、方法等,都可能導致這個值產(chǎn)生變化。我想這種方式適用于這樣的場景:
開發(fā)者認為每次修改類后就需要生成新的版本號,不想向下兼容,操作就是刪除原有serialVesionUid聲明語句,再自動生成一下。
以下內容轉自http://blog.csdn.net/jimforme/article/details/5120587
在很多應用中,需要對某些對象進行序列化,讓它們離開內存空間,入住物理硬盤,以便長期保存。比如最常見的是Web服務器中的Session對象,當有10萬用戶并發(fā)訪問,就有可能出現(xiàn)10萬個Session對象,內存可能吃不消,于是Web容器就會把一些seesion先序列化到硬盤中,等要用了,再把保存在硬盤中的對象還原到內存中,說白了,就是能將一個2進制文件變成內存中的對象。在JAVA中,要實現(xiàn)這種機制,只要實現(xiàn)Serializable接口就可以了,先看下面這個簡單例子,serialVersionUID稍后引出。我們先定義一個簡單的Person類,然后創(chuàng)建這個對象,最后序列化它到一個文件。
/*****(Person類)*******/ import java.io.Serializable; public class Person implements Serializable { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }
?
/*****(將對象序列化到一個文件)*******/
import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class WhySerialversionUID { public static void main(String[] args) throws Exception { Person person= new Person(); person.setName("jack"); ObjectOutputStream oo = new ObjectOutputStream (new FileOutputStream(new File("E://jack.test"))); oo.writeObject(person); oo.close();
?
/*****(通過以下方法可以正常的將文件中保存的對象還原到內存中)*******/
import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class WhySerialversionUID { public static void main(String[] args) throws Exception { ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("E://jack.test")));Person person = (Person)ois.readObject(); String name= person.getName();System.Out.Print("name is: "+name);
一切都那么順利,但是如果在序列化之后,Person這個類發(fā)生了改變呢?比如,多了一個成員變量。我們做如下試驗,還是先將對象序列化到一個文件中,之后在Person這個類中添加一個成員變量,如下:?
import java.io.Serializable; public class Person implements Serializable { private String name; //添加這么一個成員變量 private String address; public String getName() { return name; } public void setName(String name) { this.name = name; } }
?
之后,我們再去運行一下還原,就發(fā)現(xiàn)運行出錯了,會報如下錯誤:
Exception in thread “main” java.io.InvalidClassException: Person; local class incompatible: stream classdesc serialVersionUID = 8383901821872620925, local class serialVersionUID = -763618247875550322
意思就是說,文件流中的class和classpath中的class,也就是修改過后的class,不兼容了,處于安全機制考慮,程序拋出了錯誤,并且拒絕載入。那么如果我們真的有需求要在序列化后添加一個字段或者方法呢?應該怎么辦?那就是自己去指定serialVersionUID。之前,在我們的例子中,我們是沒有指定serialVersionUID的,那么java編譯器會自動給這個class進行一個摘要算法,類似于指紋算法,只要這個文件多一個空格,得到的UID就會截然不同的,可以保證在這么多類中,這個編號是唯一的。所以,我們添加了一個字段后,由于沒有顯指定serialVersionUID,編譯器又為我們生成了一個UID,當然和前面保存在文件中的那個不會一樣了,于是就出現(xiàn)了2個號碼不一致的錯誤。因此,只要我們自己指定了serialVersionUID,就可以在序列化后,去添加一個字段,或者方法,而不會影響到后期的還原,還原后的對象照樣可以使用,而且還多了方法可以用,呵呵。但是serialVersionUID我們怎么去生成呢?你可以寫1,也可以寫2,都無所謂,但是最好還是按照摘要算法,生成一個惟一的指紋數(shù)字,eclipse可以自動生成的,jdk也自帶了這個工具。一般寫法類似于
private static final long serialVersionUID = -763618247875550322L;在引用serializable這個類的前面有一個感嘆號,單擊這個感嘆號后會有提示,一個是默認的,一個為此類自動產(chǎn)生一個SerialVersionUID!
總結
以上是生活随笔為你收集整理的关于serialVersionUID的说明的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【搜索引擎基础知识1】搜索引擎基本架构
- 下一篇: 【搜索引擎Jediael开发笔记】v0.