首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 物件序列化與反序列化深度解析:serialVersionUID 版本控制實戰

     編輯:Java 相關知識

一、核心概念

  • 序列化:將物件轉為位元組序列,寫入檔案或網路傳輸。
  • 反序列化:從位元組序列重建物件。
  • 用途:物件持久化(如 Session 鈍化)、RMI/分散式呼叫、快取儲存。

二、JDK 核心 API

類別關鍵方法說明
ObjectOutputStreamwriteObject(Object)將物件序列化至輸出流
ObjectInputStreamreadObject()從輸入流反序列化為物件

只有實作 Serializable 或 Externalizable 介面的類別才能被序列化。

三、完整範例

1. 實體類別

import java.io.Serializable;

public class Person implements Serializable {
    private static final long serialVersionUID = -5809782578272943999L; // 強烈建議顯式宣告
    private int age;
    private String name;
    private String sex;
    // Getter/Setter 略
}

2. 序列化與反序列化工具

import java.io.*;

public class SerializationDemo {
    private static final String FILE = "E:/Person.ser";

    public static void serialize(Person p) throws IOException {
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(FILE))) {
            oos.writeObject(p);
            System.out.println("序列化成功");
        }
    }

    public static Person deserialize() throws IOException, ClassNotFoundException {
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(FILE))) {
            Person p = (Person) ois.readObject();
            System.out.println("反序列化成功");
            return p;
        }
    }

    public static void main(String[] args) throws Exception {
        Person p = new Person();
        p.setName("Gacl"); p.setAge(25); p.setSex("男");
        serialize(p);
        Person p2 = deserialize();
        System.out.println(p2.getName() + " " + p2.getAge() + " " + p2.getSex());
    }
}

四、serialVersionUID 版本控制機制

為什麼需要它?

反序列化時,JVM 會比較「流中的 serialVersionUID」與「當前類別的 serialVersionUID」。不一致拋出 InvalidClassException。

兩種產生方式

方式範例特點
預設 1Lprivate static final long serialVersionUID = 1L;簡單,但類別結構變更時需手動維護
演算法產生(預設)private static final long serialVersionUID = 4603642343377807741L;基於類別簽名雜湊,結構微調即改變,極嚴格

實戰:類別演進兼容

// v1:已序列化到磁碟
class Customer implements Serializable {
    private static final long serialVersionUID = -5182532647273106745L; // 固定版本號
    private String name;
    private int age;
    // 建構子、toString 略
}

// v2:新增 sex 欄位,但 serialVersionUID 不變
class Customer implements Serializable {
    private static final long serialVersionUID = -5182532647273106745L; // 同版本號
    private String name;
    private int age;
    private String sex; // 新增
    // 相容舊資料:反序列化時 sex 為 null,不拋異常
}

結果:舊資料可正常反序列化,新欄位預設為 null/0,達到向前兼容。

何時應改變 serialVersionUID?

  • 不兼容變更:移除欄位、修改欄位型別、變更繼承結構 → 必須改版本號,強制舊資料失效。
  • 兼容變更:新增欄位、新增/移除方法、實作新介面 → 保持版本號不變。

五、進階:自訂序列化邏輯

實作 private void writeObject(ObjectOutputStream) 與 private void readObject(ObjectInputStream) 可控制敏感欄位(如密碼)不序列化、或處理 transient 欄位還原。

六、最佳實踐清單

  1. 所有可序列化類別顯式宣告 serialVersionUID。
  2. 敏感資料(密碼、Token)標記 transient 或自訂 writeObject 排除。
  3. 跨 JVM 部署時,確保雙端類別版本一致(建議共用 common-module jar)。
  4. 大型物件圖考慮 Externalizable 或 Protobuf/Avro 等高效二進制格式。

總結

Java 序列化機制核心在於 serialVersionUID 版本協商。顯式固定版本號、理解兼容/不兼容變更規則、善用 transient 與自訂序列化,即能在分散式系統中安全、高效地傳遞物件狀態。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved