關於serialVersionUID的說明

關於serialVersionUID的說明java

一、爲何要使用serialVersionUID
   (1)對於實現了Serializable接口的類,能夠將其序列化輸出至磁盤文件中,同時會將其serialVersionUID輸出到文件中。
   (2)而後有須要使用時,再從磁盤將對象內容及serialVersionUID讀入內容中的某個對象。
   (3)將磁盤內容讀入對象時,須要進行強制類型轉換,如Person person = (Person)ois.readObject(); 
   (4) 此時,將對比從磁盤讀入的Serializable與對象所屬類(如Person)的Serializable,若兩者一致,則轉換成功。若兩者不一致,則轉換失敗,並拋出InvalidClassException。
     若是沒有爲類指定serialVersionUID,則JVM會自動根據類的內容生成一個serialVersionUID,類中的任何變化均會致使serialVersionUID的變化,如新增一個空格。

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

二、什麼時候應該修改serialVersionUID
  若對象已經修改較多或者修改爲不兼容的模式,致使原來輸出到磁盤的內容不該再轉換至原對象,此時則應該修改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.安全

三、如何建立serialVersionUID
    在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便可。
  對於第一種,須要瞭解哪些狀況是可兼容的,哪些根本就不兼容。 
  在可兼容的前提下,能夠保留舊版本號,若是不兼容,或者想讓它不兼容,就手工遞增版本號。
  1->2->3.....
  第二種方式,是根據類的結構產生的hash值。增減一個屬性、方法等,均可能致使這個值產生變化。我想這種方式適用於這樣的場景:

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

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

[Java] 純文本查看 複製代碼
?eclipse

/(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;this

}

} spa

[Java] 純文本查看 複製代碼
?.net

/(將對象序列化到一個文件)**/
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();

[Java] 純文本查看 複製代碼
?

/(經過如下方法能夠正常的將文件中保存的對象還原到內存中)**/
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這個類發生了改變呢?好比,多了一個成員變量。咱們作以下試驗,仍是先將對象序列化到一個文件中,以後在Person這個類中添加一個成員變量,以下:

[Java] 純文本查看 複製代碼
?

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!

文章摘自::https://blog.csdn.net/jediael...

相關文章
相關標籤/搜索