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

Java 每日一題:final 修飾的實例變量在序列化與反序列化中的行為解析

     編輯:Java 綜合教學

題目代碼

package Nov2016;
import java.io.Serializable;

public class Ques1115 implements Serializable {
    private static final long serialVersionUID = 1L;
    public final int num = init(); // 通過方法賦值

    public int init() {
        return 123;
    }
}

問題描述

  1. 先將對象序列化寫入磁碟。
  2. 修改 init() 返回值為 321(保持 serialVersionUID 不變)。
  3. 反序列化讀取磁碟中舊對象,請問 num 的值是多少?

核心知識點:final 實例變量的序列化語義

Java 序列化規範對 final 修飾的實例變量有特殊處理:

  • 編譯時常量(static final 基本類型或 String,且賦值為常量表達式):序列化時不寫入流中,反序列化時直接使用類中定義的常量值。
  • 運行時賦值的 final 變量(如構造器、實例初始化器、方法調用賦值):會被序列化,反序列化時忽略類中當前的賦值邏輯,直接還原流中的值。

本題中 num = init() 屬於「運行時賦值」,因此序列化時將 123 寫入流。

答案揭曉

輸出結果為 123。

反序列化時,JVM 從對象流讀取已存儲的 123 賦給 num,完全跳過當前類定義中的 init() 邏輯(即便已改為返回 321)。這保證了「對象狀態的持久化一致性」。

延伸對比:20161114 題目

前一天題目中 num 在構造器賦值(public Ques1114(){ num = 123; }),同屬「運行時賦值」,行為一致,反序列化同樣輸出 123。

最佳實踐提醒

  1. 若希望反序列化後獲得最新計算值,請移除 final或改用 transient + 反序列化後重新計算。
  2. 修改類結構時務必維護 serialVersionUID,否則會拋出 InvalidClassException。
  3. 生產環境慎用「方法調用賦值 final 變量」,增加維護認知負擔。

理解此機制,有助於避免分布式系統中因序列化不一致導致的難以排查的業務 Bug。

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