36.Java序列化與反序列化是什么
- 序列化就是把Java對象轉換成字節流(二進制)。
- 把對象保存到本地文件或網絡傳輸。因為Java對象在JVM的堆內存中,JVM堆不存在了,對象也就不在了。
- 反序列化就是把字節流轉換為對象
- 從文件或者網絡里獲取字節流,通過反序列化就可以重建對象
為什么需要序列化與反序列化?
進行持久化或者網絡傳輸時需要序列化與反序列化。
跨平臺和跨語言通信,序列化為二進制文件,可以在不同平臺和語言解析。
Java對象序列化不僅僅保留一個對象的數據,也會遞歸保留對象引用的每個對象的數據
序列化實現的方式有哪些?
-
實現serializable接口或者Externalizable接口
-
Serializable接口
-
特點:
- 簡單易用:只需實現接口即可。
- 默認行為:自動序列化所有非
transient
和非靜態字段。 - 版本控制:通過
serialVersionUID
控制類版本兼容性。
-
缺點:
- 性能較差:生成的字節流較大,效率較低。
- 跨語言不兼容:只能用于 Java 系統內部。
- 安全性問題:反序列化不可信數據可能導致漏洞。
-
public class Person implements Serializable {private static final long serialVersionUID = 1L;private String name;private int age;// 構造方法、getter/setter }// 序列化 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.ser")); oos.writeObject(new Person("Alice", 30));// 反序列化 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.ser")); Person person = (Person) ois.readObject();
-
-
自定義序列化(
Externalizable
接口)-
特點:
- 完全控制序列化邏輯:可選擇性地序列化字段。
- 更靈活:適合需要優化存儲或傳輸效率的場景。
-
缺點:
- 開發成本高:需要手動編寫序列化/反序列化邏輯。
-
public class Person implements Externalizable {private String name;private int age;@Overridepublic void writeExternal(ObjectOutput out) throws IOException {out.writeUTF(name);out.writeInt(age);}@Overridepublic void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {name = in.readUTF();age = in.readInt();} }
-
-
什么是serialVersionUID
用來表示類的不同版本的兼容性。
來驗證版本是否一致,JVM在反序列化時,拿到傳過來的字節碼文件,用字節碼文件的UID去和本地的類文件的UID去比對,如果一致就會進行反序列化。
為什么還要顯示指定serialVersionUID的值
- 如果不顯示指定,JVM就會在反序列化時新生成一個UID去和本地類的UID去對比
- 如果顯示指定了,JVM任然會去生成UID,但是UID值是我們顯示指定的值,會去和本地的顯示指定的UID去對比,這樣舊和新的UID都是一致的,是我們顯示指定的。
- 在實際開發中,編寫的類會一直不斷迭代,如果修改了類,UID就會改變,所以我們顯示指定一個UID,保持UID一致。
serialVersionUID什么時候修改?
序列化類新增屬性時,不要修改UID,避免反序列化失敗。如果完全不兼容升級,避免反序列化混亂,修改UID。
Java 序列化中如果有些字段不想進行序列化,怎么辦?
對于不想進行序列化的變量,使用 transient 關鍵字修飾。transient只能修飾變量,不能修飾類和方法。反序列化后,transient修飾的值會設為初始值,如int類型就會為0,對象類型就會為null。
靜態變量會被序列化嗎?
sient 關鍵字修飾。transient只能修飾變量,不能修飾類和方法。反序列化后,transient修飾的值會設為初始值,如int類型就會為0,對象類型就會為null。
靜態變量會被序列化嗎?
不會,因為序列化是針對對象而言的,而靜態變量會隨著類的加載而加載,優先于對象存在。serialVersionUID也被static修飾, 為什么serialVersionUID會被序列化?其實serialVersionUID屬性并沒有被序列化, JVM在序列化對象時會自動生成一個serialVersionUID, 然后將我們顯示指定的serialVersionUID屬性值賦給自動生成的serialVersionUID。