1.什麼是序列化和反序列化java
序列化就是將java對象轉成字節序列的過程;反序列化就是將字節序列轉成java對象的過程。算法
java中,序列化的目的一種是須要將對象保存到硬盤上,一種是對象須要在網絡中傳輸。json
2.序列化和反序列化的方式網絡
序列化和反序列化有不少種方式,如JDK類庫中提供的序列化API、經常使用的json工具類等。本篇博客使用JDK提供的序列化API進行演示。重點說明serialVersionUID的做用。工具
假設如今有一個Student類,咱們要對Student類進行序列化操做測試
①該類必須實現Serializable接口this
public class Student implements Serializable{ private static final long serialVersionUID = -595470438262181967L; private String name ; private String sex; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } }
②在main方法中執行序列化和反序列化操做spa
public static void main(String[] args) throws Exception { //序列化 OutputStream os = new FileOutputStream(new File("D://student.txt")); ObjectOutputStream oos = new ObjectOutputStream(os); Student student = new Student(); student.setName("張三"); student.setSex("男"); oos.writeObject(student); //反序列化 InputStream is = new FileInputStream(new File("D://student.txt")); ObjectInputStream ois = new ObjectInputStream(is); Student student1 = new Student(); student1 = (Student) ois.readObject(); System.out.println(student1.getName()); }
輸出結果:張三code
即student1對象在反序列化時進行了賦值對象
3.爲何要serialVersionUID
serialVersionUID: 字面意思上是序列化的版本號,凡是實現Serializable接口的類都有一個表示序列化版本標識符的靜態變量。
(1)下面進行測試,若是沒有serialVersionUID會出現什麼?
①去掉Student類中的serialVersionUID屬性。執行main方法,結果顯示序列化成功!輸出張三
②修改Student類,在Student類中添加number字段
public class Student implements Serializable{ private String name ; private String sex; private String number; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } }
不執行序列化方法,只執行反序列化方法,結果出現異常:
Exception in thread "main" java.io.InvalidClassException: com.iot.study.serialize.Student; local class incompatible: stream classdesc serialVersionUID = -595470438262181967, local class serialVersionUID = -4254220179260112271 at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:621) at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1623) at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1518) at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1774) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351) at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371) at com.iot.study.serialize.Client.main(Client.java:35)
意思是原來序列化的時候(沒有指定serialVersionUID)硬盤存的class的 serialVersionUID = -595470438262181967,而當前class的serialVersionUID = -4254220179260112271。 兩者不同,沒法反序列化。
緣由分析:
serialVersionUID沒有指定時,java編譯器會自動給這個class進行一個摘要算法,相似於指紋算法,只要這個文件 多一個空格,獲得的UID就會大相徑庭的,能夠保證在這麼多類中,這個編號是惟一的。因此,添加了一個number字段後,因爲沒有顯指定 serialVersionUID,編譯器又爲咱們生成了一個UID,固然和前面保存在文件中的那個不會同樣了,因而就出現了2個序列化版本號不一致的錯誤。
(2)指定serialVersionUID測試
若是爲Student類顯示的指定serialVersionUID,那麼在序列化和反序列化的時候,即便修改了Student類中的部份內容,也能序列化成功。
4.serialVersionUID的取值
serialVersionUID的取值是Java運行時環境根據類的內部細節自動生成的。若是對類的源代碼做了修改,再從新編譯,新生成的類文件的serialVersionUID的取值有可能也會發生變化。
類的serialVersionUID的默認值徹底依賴於Java編譯器的實現,對於同一個類,用不一樣的Java編譯器編譯,有可能會致使不一樣的 serialVersionUID,也有可能相同。爲了提升serialVersionUID的獨立性和肯定性,強烈建議在一個可序列化類中顯示的定義serialVersionUID,爲它賦予明確的值。
顯式地定義serialVersionUID有兩種用途: 一、 在某些場合,但願類的不一樣版本對序列化兼容,所以須要確保類的不一樣版本具備相同的serialVersionUID; 二、 在某些場合,不但願類的不一樣版本對序列化兼容,所以須要確保類的不一樣版本具備不一樣的serialVersionUID。