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

【Java 每日一題】常量折疊陷阱:20161116 解析

     編輯:Java 綜合教學

【Java 每日一題】常量折疊陷阱:20161116 解析

這道題目揭示 Java 編譯期常量折疊優化導致的「修改常量值不重新編譯調用方,運行時仍讀取舊值」的經典行為。

題目代碼

// Ques1116.java
public class Ques1116 {
    public static void main(String[] args) {
        System.out.println("常量是" + Const.NUM);
    }
}

// Const.java
public class Const {
    public final static int NUM = 110;
}

操作步驟與結果

  1. javac Ques1116.java Const.java → java Ques1116 輸出 110
  2. 修改 Const.NUM = 120
  3. 僅重新編譯 Const:javac Const.java
  4. 不重新編譯 Ques1116,直接運行:java Ques1116
  5. 輸出仍為 110!

原理深度解析

  • final static 基本類型/字符串屬於 編譯期常量 (JLS 15.28)
  • 編譯器在編譯 Ques1116 時,將 Const.NUM 的值 內聯 到字節碼常量池:ldc 110
  • 運行時 Ques1116 類文件 不再依賴 Const 類,甚至刪除 Const.class 也能運行
  • 單獨重新編譯 Const 只更新 Const.class 常量池,Ques1116.class 仍持有舊值 110

驗證方法

javap -c Ques1116.class
# 輸出包含:ldc #2 // int 110
# 無 CONSTANT_Class_info 指向 Const

最佳實踐與避坑

  1. 修改公共常量後,務必全量重新編譯所有依賴模塊 (Maven/Gradle clean compile 自動處理)
  2. 需運行期動態讀取的配置,不要用 final static 基本類型,改用:
    • public static final String CONFIG = "..."; (非基本類型/非字符串字面量)
    • 配置中心 / 屬性文件 / 環境變量
  3. 理解 二進制兼容性:常量折疊屬於源碼兼容、非二進制兼容變更

延伸思考

若 NUM 為 Integer 或自定義對象,編譯器不會折疊,運行時會動態讀取最新值。這也是為何 String 常量折疊行為與包裝類型不同的原因。

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