serialVersionUID作用全面解析
serialVersionUID適用于Java的序列化機(jī)制。簡(jiǎn)單來(lái)說(shuō),Java的序列化機(jī)制是通過(guò)判斷類(lèi)的serialVersionUID來(lái)驗(yàn)證版本一致性的。在進(jìn)行反序列化時(shí),JVM會(huì)把傳來(lái)的字節(jié)流中的serialVersionUID與本地相應(yīng)實(shí)體類(lèi)的serialVersionUID進(jìn)行比較,如果相同就認(rèn)為是一致的,可以進(jìn)行反序列化,否則就會(huì)出現(xiàn)序列化版本不一致的異常,即是InvalidCastException。
serialVersionUID有兩種顯示的生成方式:
一是默認(rèn)的1L,比如:private static final long serialVersionUID = 1L;
二是根據(jù)類(lèi)名、接口名、成員方法及屬性等來(lái)生成一個(gè)64位的哈希字段,比如:
private static final long serialVersionUID = xxxxL;
當(dāng)一個(gè)類(lèi)實(shí)現(xiàn)了Serializable接口,如果沒(méi)有顯示的定義serialVersionUID,Eclipse會(huì)提供相應(yīng)的提醒。面對(duì)這種情況,我們只需要在Eclipse中點(diǎn)擊類(lèi)中warning圖標(biāo)一下,Eclipse就會(huì) 自動(dòng)給定兩種生成的方式。如果不想定義,在Eclipse的設(shè)置中也可以把它關(guān)掉的,設(shè)置如下:
Window ==> Preferences ==> Java ==> Compiler ==> Error/Warnings ==> Potential programming problems
將Serializable class without serialVersionUID的warning改成ignore即可。
當(dāng)實(shí)現(xiàn)java.io.Serializable接口的類(lèi)沒(méi)有顯式地定義一個(gè)serialVersionUID變量時(shí)候,Java序列化機(jī)制會(huì)根據(jù)編譯的Class自動(dòng)生成一個(gè)serialVersionUID作序列化版本比較用,這種情況下,如果Class文件(類(lèi)名,方法明等)沒(méi)有發(fā)生變化(增加空格,換行,增加注釋等等),就算再編譯多次,serialVersionUID也不會(huì)變化的。
如果我們不希望通過(guò)編譯來(lái)強(qiáng)制劃分軟件版本,即實(shí)現(xiàn)序列化接口的實(shí)體能夠兼容先前版本,就需要顯式地定義一個(gè)名為serialVersionUID,類(lèi)型為long的變量,不修改這個(gè)變量值的序列化實(shí)體都可以相互進(jìn)行串行化和反串行化。
下面用代碼說(shuō)明一下serialVersionUID在應(yīng)用中常見(jiàn)的幾種情況。
(1)序列化實(shí)體類(lèi)
import java.io.Serializable; public class Person implements Serializable { private static final long serialVersionUID = 1234567890L; public int id; public String name; public Person(int id, String name) { this.id = id; this.name = name; } public String toString() { return "Person: " + id + " " + name; } }
(2)序列化功能:
import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; public class SerialTest { public static void main(String[] args) throws IOException { Person person = new Person(1234, "wang"); System.out.println("Person Serial" + person); FileOutputStream fos = new FileOutputStream("Person.txt"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(person); oos.flush(); oos.close(); } }
(3)反序列化功能:
import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; public class DeserialTest { public static void main(String[] args) throws IOException, ClassNotFoundException { Person person; FileInputStream fis = new FileInputStream("Person.txt"); ObjectInputStream ois = new ObjectInputStream(fis); person = (Person) ois.readObject(); ois.close(); System.out.println("Person Deserial" + person); } }
情況一:假設(shè)Person類(lèi)序列化之后,從A端傳輸?shù)紹端,然后在B端進(jìn)行反序列化。在序列化Person和反序列化Person的時(shí)候,A端和B端都需要存在一個(gè)相同的類(lèi)。如果兩處的serialVersionUID不一致,會(huì)產(chǎn)生什么錯(cuò)誤呢?
【答案】可以利用上面的代碼做個(gè)試驗(yàn)來(lái)驗(yàn)證:
先執(zhí)行測(cè)試類(lèi)SerialTest,生成序列化文件,代表A端序列化后的文件,然后修改serialVersion值,再執(zhí)行測(cè)試類(lèi)DeserialTest,代表B端使用不同serialVersion的類(lèi)去反序列化,結(jié)果報(bào)錯(cuò):
Exception in thread "main" java.io.InvalidClassException: test.Person; local class incompatible: stream classdesc serialVersionUID = 1234567890, local class serialVersionUID = 123456789
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:560)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1580)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1493)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1729)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1326)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:348)
at test.DeserialTest.main(DeserialTest.java:15)
情況二:假設(shè)兩處serialVersionUID一致,如果A端增加一個(gè)字段,然后序列化,而B(niǎo)端不變,然后反序列化,會(huì)是什么情況呢?
【答案】新增 public int age; 執(zhí)行SerialTest,生成序列化文件,代表A端。刪除 public int age,反序列化,代表B端,最后的結(jié)果為:執(zhí)行序列化,反序列化正常,但是A端增加的字段丟失(被B端忽略)。
情況三:假設(shè)兩處serialVersionUID一致,如果B端減少一個(gè)字段,A端不變,會(huì)是什么情況呢?
【答案】序列化,反序列化正常,B端字段少于A端,A端多的字段值丟失(被B端忽略)。
情況四:假設(shè)兩處serialVersionUID一致,如果B端增加一個(gè)字段,A端不變,會(huì)是什么情況呢?
驗(yàn)證過(guò)程如下:
先執(zhí)行SerialTest,然后在實(shí)體類(lèi)Person增加一個(gè)字段age,如下所示,再執(zhí)行測(cè)試類(lèi)DeserialTest.
import java.io.Serializable; public class Person implements Serializable { private static final long serialVersionUID = 123456789L; public int id; public String name; public int age; public Person(int id, String name) { this.id = id; this.name = name; } public String toString() { return "Person: " + id + " " + name; } }
相應(yīng)的修改測(cè)試類(lèi)DeserialTest,打印出age的值。
import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; public class SerialTest { public static void main(String[] args) throws IOException { Person person = new Person(1234, "wang"); System.out.println("Person Serial" + person + " age:" + person.age); FileOutputStream fos = new FileOutputStream("Person.txt"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(person); oos.flush(); oos.close(); } }
結(jié)果為:
Person Deserial Person: 1234 wang age: 0
說(shuō)明序列化,反序列化正常,B端新增加的int字段被賦予了默認(rèn)值0。
最后通過(guò)下面的圖片,總結(jié)一下上面的幾種情況。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Spring加載配置和讀取多個(gè)Properties文件的講解
今天小編就為大家分享一篇關(guān)于Spring加載配置和讀取多個(gè)Properties文件的講解,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-03-03Java設(shè)計(jì)模式之工廠模式(Factory模式)介紹
這篇文章主要介紹了Java設(shè)計(jì)模式之工廠模式(Factory模式)介紹,本文講解了為何使用工廠模式、工廠方法、抽象工廠、Java工廠模式舉例等內(nèi)容,需要的朋友可以參考下2015-03-03spring(java,js,html) 截圖上傳圖片實(shí)例詳解
這篇文章主要介紹了spring(java,js,html) 截圖上傳圖片實(shí)例詳解的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-07-07Java封裝數(shù)組實(shí)現(xiàn)包含、搜索和刪除元素操作詳解
這篇文章主要介紹了Java封裝數(shù)組實(shí)現(xiàn)包含、搜索和刪除元素操作,結(jié)合實(shí)例形式分析了java針對(duì)數(shù)組元素的查找、刪除、判斷等相關(guān)操作封裝與使用技巧,需要的朋友可以參考下2020-03-03java基礎(chǔ)之泛型知識(shí)點(diǎn)總結(jié)
這篇文章主要介紹了java基礎(chǔ)之泛型知識(shí)點(diǎn)總結(jié),文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java基礎(chǔ)的小伙伴們有很好的幫助,需要的朋友可以參考下2021-04-04JSON 與對(duì)象、集合之間的轉(zhuǎn)換的示例
在開(kāi)發(fā)過(guò)程中,經(jīng)常需要和別的系統(tǒng)交換數(shù)據(jù),數(shù)據(jù)交換的格式有XML、JSON等,JSON作為一個(gè)輕量級(jí)的數(shù)據(jù)格式比xml效率要高,本篇文章主要介紹了JSON 與 對(duì)象 、集合 之間的轉(zhuǎn)換,有興趣的可以了解一下。2017-01-01解決springmvc整合Mybatis的Log4j日志輸出問(wèn)題
這篇文章主要介紹了解決springmvc整合Mybatis的Log4j日志輸出問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07