Java序列化和反序化
一、什么是序列化和反序列化
Java序列化就是指把Java對象轉換為字節序列的過程
Java反序列化就是指把字節序列恢復為Java對象的過程。
二、為什么要把一個對象序列化
正常情況下,Java new出的對象,是保存在內存當中的,是不能持久化保存的,也不能直接在網絡中傳輸,如何解決呢?就是把Java對象轉換為byte字節數據,以字節的方式去實現持久化保存和網絡傳輸。而反序列化,就是把須列化后的數據,重新恢復成內存中的Java對象。
總之,序列化,就是對一個Java對象的保存和重建的過程。
三、Java實現序列化的過程
為了讓一個Java對象能序列化,我們需要為這個Java對象實現Serializable接口,像下面這樣,這個方法和普通的Bean來說,多繼承了這個接口,這個接口沒有實現實現任何方法,它是為什么告訴編譯器,這個接口可以序列化。
@Data public class User implements Serializable { private String name; private int age; private String sex; private String phone; }
這個類可以序列化了,但如何序列化讓它能本地存儲呢?執行下面的write方法,將會在D盤根目錄下創建User類的序列化文件,執行read方法可以把序列化文件轉變成對象。
public class Client { @Test public void write() throws Exception{ User user = new User(); user.setAge(15); user.setName("張三"); user.setPhone("123"); FileOutputStream fileOutputStream = new FileOutputStream("D://out.txt"); ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); objectOutputStream.writeObject(user); } @Test public void read() throws Exception{ FileInputStream fileInputStream = new FileInputStream("D://out.txt"); ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream); User o = (User)objectInputStream.readObject(); System.out.println(o.toString()); } }
read方法運行結果,序列化出來的對象,擁有序列化之前對象的值。
四、不能被序列化的對象
Java對象中,如果一個字段被transient修飾,或者這個字段是static靜態字段,這個類將不會被序列化,意味著,這個對象被序列化后,再次反序列化成Java對象后,對于的字段值為null。
五、序列號的作用
我們的類是不斷的變動的,我們把一個對象序列化到本地文件后,有一天,這個對象的類發送了改變,我們用這個改變后的類接收序號化文件,會發生什么?把name和age注釋掉,然后去反序列化。
public class User implements Serializable { // private String name; // // transient private int age; private String sex; private String phone; } public class Client { @Test public void write() throws Exception{ User user = new User(); // user.setAge(15); // user.setName("張三"); user.setPhone("123"); FileOutputStream fileOutputStream = new FileOutputStream("D://out.txt"); ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); objectOutputStream.writeObject(user); } @Test public void read() throws Exception{ FileInputStream fileInputStream = new FileInputStream("D://out.txt"); ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream); User o = (User)objectInputStream.readObject(); System.out.println(o.toString()); } }
結果就是
java.io.InvalidClassException: com.example.service.demo01.User; local class incompatible: stream classdesc serialVersionUID = -118799779803260725, local class serialVersionUID = 1681826866445576943
這個報錯是什么意思?是這個類和序列化文件里的類的序列號不一樣,無法反序列化。
這里出現了一個問題,什么是序列號?
序列號是一個長整型的數據,一個類的序列號,是根據這個類的成員變量計算出來,如果成員變量發生改變,序列號也會發生改變,只有序列化文件的序列號和類的序列號相同,才能反序列化成功。
所以這個報錯就很容易理解了,在改動前,類有三個變量,序列號的值假設是3,序列化的文件也是3,刪除一個變量后,只剩兩個變量,假設序列號是2,這樣和序列化文件的序列號就不一樣了,所以無法反序列化。
有時候,我們希望,即使類發生了改變,也能反序列化成功,比如之前有現在只剩3個字段,序列化的文件有4個字段,我們只序列化現在的類有的字段,那該怎么做?
我們可以手動為一個類設置序列號,像這樣:
這樣,即使類發生了改變,但是序列號我們已經手動寫死了,之后類再怎么發生變化,反序列化也不會報錯,只會序列那化些還能對應上的值。
Java
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。