在實現了Serializable介面的class中,需要聲明一個long serialVersionUID,用來標明當前class的版本號碼,但很多人在編程時,總是不原意去聲明這個serialVersionUID,又JVM自己來產生。下面來看看serialVersionUID的作用:
1、如果在序列化寫 時的版本號碼和序列化讀 時的版本號碼,不一致,將會有異常:java.io.InvalidClassException:local class incompatible: stream classdesc serialVersionUID = …, local class serialVersionUID = …
2、那如果在class中不聲明這個屬性呢?那結果可以就會變得比較詭異了:
1)、在序列化寫 的時候,虛擬機器A會為它計算出一個serialVersionUID,計算的方法是依據class的資訊,再具體我也不清楚了。
2)、在序列化讀 的時候,虛擬機器B也會為class計算出一個serialVersionUID,然後做比較。
3)、那麼如果兩個虛擬機器是不同類型的虛擬機器,那麼計算方法可能就不一樣了,於是即使相同的class,serialVersionUID也可能會不同,不同的class的,理論上來說,也存在serialVersionUID相同的可能性,所以,serialVersionUID盡量由我們自己來指定,而不要由虛擬機器來計算。
3、那如果serialVersionUID一致,而class發生了變化呢?
1)、如果虛擬機器A中的AClass有一個屬性,而虛擬機器B中的AClass,沒有這個屬性,那麼這個屬性將被忽略,而不會有異常。
2)、如果虛擬機器A中的AClass沒有的屬性,而在虛擬機器B中多出來的屬性,那麼這個屬性將被賦予一個預設值,而不會有異常。
3)、如果虛擬機器A中的AClass有一個屬性,在虛擬機器B中的AClass也有這個屬性,但這個屬性的類型變了,比如說int變成了long,抑或其他的變化,將會有異常:java.io.InvalidClassException:incompatible types for field …
經過序列化而產生的異常都是 java.io.InvalidClassException,不會產生java.lang.ClassCastException,兩者還是有比較大的區別的,從名字上就可以看得出來。
看完你還會讓JVM自己來產生serialVersionUID嗎?你還加@SuppressWarnings("serial")嗎?在一個單機上或許看不出什麼問題,但在分散式運算、或者你需要提供jar供別人使用的時候,這個問題就會暴露。
我的另一篇文章:Java
Serializable系列化與反系列化