關於serialVersionUID的說明

https://blog.csdn.net/jediael_lu/article/details/26813153java

 

一、爲何要使用serialVersionUID算法

(1)對於實現了Serializable接口的類,能夠將其序列化輸出至磁盤文件中,同時會將其serialVersionUID輸出到文件中。安全

(2)而後有須要使用時,再從磁盤將對象內容及serialVersionUID讀入內容中的某個對象。服務器

(3)將磁盤內容讀入對象時,須要進行強制類型轉換,如Person person = (Person)ois.readObject(); 併發

(4) 此時,將對比從磁盤讀入的Serializable與對象所屬類(如Person)的Serializable,若兩者一致,則轉換成功。若兩者不一致,則轉換失敗,並拋出InvalidClassException。eclipse

若是沒有爲類指定serialVersionUID,則JVM會自動根據類的內容生成一個serialVersionUID,類中的任何變化均會致使serialVersionUID的變化,如新增一個空格。工具

所以,若一個類沒有指定serialVersionUID,並且發生了變化,則讀取磁盤中的對象時就會報錯。this

 

二、什麼時候應該修改serialVersionUIDspa

若對象已經修改較多或者修改爲不兼容的模式,致使原來輸出到磁盤的內容不該再轉換至原對象,此時則應該修改serialVersionUID。.net

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.

 

三、如何建立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,一種是生成一個很大的數,這兩種有什麼區別呢?

看上去,好像每一個類的這個類不一樣,彷佛這個SerialVersionUid在類之間有某種關聯。其實否則,兩種均可以,從JDK文檔也看不出這一點。咱們只要保證在同一個類中,不一樣版本根據兼容須要,是否更改SerialVersionUid便可。

對於第一種,須要瞭解哪些狀況是可兼容的,哪些根本就不兼容。 參考文檔:http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf

在可兼容的前提下,能夠保留舊版本號,若是不兼容,或者想讓它不兼容,就手工遞增版本號。

1->2->3.....


第二種方式,是根據類的結構產生的hash值。增減一個屬性、方法等,均可能致使這個值產生變化。我想這種方式適用於這樣的場景:

開發者認爲每次修改類後就須要生成新的版本號,不想向下兼容,操做就是刪除原有serialVesionUid聲明語句,再自動生成一下。

 


如下內容轉自http://blog.csdn.net/jimforme/article/details/5120587

在不少應用中,須要對某些對象進行序列化,讓它們離開內存空間,入住物理硬盤,以便長期保存。好比最多見的是Web服務器中的Session對象,當有10萬用戶併發訪問,就有可能出現10萬個Session對象,內存可能吃不消,因而Web容器就會把一些seesion先序列化到硬盤中,等要用了,再把保存在硬盤中的對象還原到內存中,說白了,就是能將一個2進制文件變成內存中的對象。在JAVA中,要實現這種機制,只要實現Serializable接口就能夠了,先看下面這個簡單例子,serialVersionUID稍後引出。咱們先定義一個簡單的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; 
    } 
}

 

/*****(將對象序列化到一個文件)*******/

    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();
    }

 

 

/*****(經過如下方法能夠正常的將文件中保存的對象還原到內存中)*******

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這個類發生了改變呢?好比,多了一個成員變量。咱們作以下試驗,仍是先將對象序列化到一個文件中,以後在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; 
    } 
}

以後,咱們再去運行一下還原,就發現運行出錯了,會報以下錯誤:


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,固然和前面保存在文件中的那個不會同樣了,因而就出現了2個號碼不一致的錯誤。所以,只要咱們本身指定了serialVersionUID,就能夠在序列化後,去添加一個字段,或者方法,而不會影響到後期的還原,還原後的對象照樣可使用,並且還多了方法能夠用,呵呵。可是serialVersionUID咱們怎麼去生成呢?你能夠寫1,也能夠寫2,都無所謂,可是最好仍是按照摘要算法,生成一個唯一的指紋數字,eclipse能夠自動生成的,

jdk也自帶了這個工具。通常寫法相似於private static final long serialVersionUID = -763618247875550322L;在引用serializable這個類的前面有一個感嘆號,單擊這個感嘆號後會有提示,一個是默認的,一個爲此類自動產生一個SerialVersionUID!

相關文章
相關標籤/搜索