【深度解析】序列化與反序列化 探析
或許很多同學像本人一樣,剛開始接觸 序列化
這個概念時,覺得也沒什麼
但是隨著我們瞭解的知識點越來越多,直到做一些Web開發時,才發現 好多POJO都需要實現Serializable介面
在本人之前的博文《詳解 序列化流 與 反序列化流》中,曾講到過Java中的有關 序列化
與 反序列化
的知識點
那麼,在本篇博文中,本人就來通過一個小demo,來講解下 序列號 的本質:
舉個栗子(Demo):
首先,本人來給出一個實現了Serializable介面的POJO類:
序列化的pojo:
package edu.youzg.test.about_serializable; import java.io.Serializable; /** * @Author: Youzg * @CreateTime: 2020-12-20 10:21 * @Description: 帶你深究Java的本質! */ public class Fan implements Serializable { private static final long serialVersionUID = 3439052454193760044L; private String name; private Integer age; private int likeNum; public Fan() { } public Fan(String name, Integer age, int likeNum) { this.name = name; this.age = age; this.likeNum = likeNum; } public static long getSerialVersionUID() { return serialVersionUID; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public int getLikeNum() { return likeNum; } public void setLikeNum(int likeNum) { this.likeNum = likeNum; } @Override public String toString() { return "Fan{" + "name='" + name + '\'' + ", age=" + age + ", likeNum=" + likeNum + '}'; } }
友情提示:
請牢記當前pojo的
serialVersionUID
:
3439052454193760044L
(其實在下面的案例中,要修改也就只會修改最後一位)
那麼,本人就先通過之前文章《詳解 序列化流 與 反序列化流》中所講到的 ObjectOutputStream類
,將目標物件序列化,並將序列化後的資訊轉存到檔案中:
序列化 pojo物件:
package edu.youzg.test.about_serializable; import edu.youzg.network_transmission.section.FileSectionInfo; import java.io.*; /** * @Author: Youzg * @CreateTime: 2020-12-20 10:25 * @Description: 帶你深究Java的本質! */ public class GenerateFileTest { public static void main(String[] args) { try { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("./prettyGril.txt")); Fan aFan = new Fan("prettyGril", 16, 666); oos.writeObject(aFan); } catch (Exception e) { // TODO: handle exception } } }
讀取並反序列化 pojo物件:
package edu.youzg.test.about_serializable; import edu.youzg.network_transmission.section.FileSectionInfo; import java.io.*; /** * @Author: Youzg * @CreateTime: 2020-12-20 10:25 * @Description: 帶你深究Java的本質! */ public class GenerateFileTest { public static void main(String[] args) { try { ObjectInputStream ois = new ObjectInputStream(new FileInputStream("./prettyGril.txt")); System.out.println("0"); Fan aFan = (Fan) ois.readObject(); System.out.println("1"); System.out.println(aFan.toString()); System.out.println(aFan == null); System.out.println(aFan.toString().equals("")); } catch (Exception e) { e.printStackTrace(); } } }
可以看到,執行結果如下:
由於在之前的博文《詳解 序列化流 與 反序列化流》中,本人已經演示過 反序列化時不加序列號 的情況了
那麼,在本文中,本人僅來展示 反序列化時序列號不一致 的情況:
反序列化時序列號不一致:
修改 序列號 為 3439052454193760045L
繼續執行上文中的 反序列化程式:
由於所展示空間有限,本人就將 控制檯內容 貼上到下方:
0
java.io.InvalidClassException: edu.youzg.test.about_serializable.Fan; local class incompatible: stream classdesc serialVersionUID = 3439052454193760044, local class serialVersionUID = 3439052454193760045
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1843)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1713)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2000)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1535)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:422)
at edu.youzg.test.about_serializable.GenerateFileTest.main(GenerateFileTest.java:28)
可以看到:
由於 反序列化時序列號不一致,反序列化失敗了!
那麼,反序列化時不加序列號
和 反序列化時序列號不一致
都會導致 反序列化失敗,
這是為什麼呢?
那麼,接下來,正片開始!
首先,我們來看看序列化後的 序列化檔案內容:
序列化 檔案內容:
IDEA開啟:
???WTF
這都什麼亂七八糟的?
二話不說,直接用 其它編輯器 檢視其 位元組碼:
位元組碼內容:
還是一團亂麻!!!
別急嘛,我們再來看看之前的序列號
:
那麼,我們將這個序列號拿計算器轉換下進位制
:
進位制轉換:
當然,我們現在只需要關心 十六進位制
即可:
2FB9 F7FC 7827 872C
在位元組碼檔案中查詢,就會找到相應的 位元組碼資訊
:
序列化的位元組碼檔案中,包含了 被序列化的pojo物件 的 全部資訊,
包括其 序列號
當我們反序列化時,就會拿自己的pojo物件的序列號與其對比
若是 不存在序列號(沒有實現Serializable介面),就會序列化失敗!
如此一來,相信就能徹底解釋清楚 序列號 的 重要作用 的 原因 了!