代碼片段中,多個 byte 賦值語句編譯結果截然不同:
int a = 1;
final int X = a; // 非常量表達式
final int Y = 10; // 編譯期常量表達式
// byte b1 = X; // 錯誤:Type mismatch
byte b2 = Y; // 正常:編譯器自動窄化轉換
byte b3 = Y + 1; // 正常:常量折疊後仍在 byte 範圍
// byte b4 = (4 < 5) ? X : 4; // 錯誤
byte b5 = (4 < 5) ? Y : 4; // 正常
byte b6 = 12;
byte b7 = (4 < 5) ? b6 : 4; // 正常
// byte b8 = b6 + 4; // 錯誤:非常量表達式
byte b9 = (4 < 5) ? b6 : ('3' + 1); // 正常
// byte b10 = (4 < 5) ? b6 : '3'; // 錯誤:'3' 是 char,三元運算類型提升為 int
Java 允許 編譯期常量表達式 在賦值給 byte/short/char 時自動窄化,前提:
byte:-128~127)。final int X = a; vs final int Y = 10;X:初始化表達式 a 非常量(運行時才確定值),故 X 不是 常量表達式 → 賦值 byte 需強制轉換。Y:初始化為字面量 10,屬常量表達式 → 編譯器直接生成 bipush 10 指令,隱式完成 int→byte。? : 的類型推導(JLS 15.25)三元運算符結果類型由第二、三操作數決定,遵循「數值類型提升」規則:
(4 < 5) ? Y : 4:Y 為常量 int,4 為 int 常量 → 結果類型 int,但因整體為常量表達式且值在範圍內,允許窄化賦值 byte。(4 < 5) ? X : 4:X 非常量 int → 結果類型 int 且非常量表達式 → 禁止隱式窄化。(4 < 5) ? b6 : '3':b6 為 byte,'3' 為 char → 雙方提升至 int → 結果類型 int 且非常量 → 錯誤。(4 < 5) ? b6 : ('3' + 1):'3' + 1 編譯期計算為 52 (int 常量),b6 為 byte 變量 → 結果類型 int 但整體為常量表達式(因條件為常量 true,編譯器可推導結果為常量) → 允許窄化。b6 + 4 為何報錯?b6 為變量,b6 + 4 運行時計算 → 非常量表達式 → int 不能隱式賦值給 byte。
使用 javap -c 查看字節碼:
byte b2 = Y; → bipush 10(直接推 byte 值)byte b1 = X; 若強制編譯通過 → iload X; i2b; istore b1(顯式 i2b 截斷)static final 常量 初始化 final 變量,獲得常量表達式優勢。byte b = (byte) (X + 1); 消除歧義,提高可讀性。int 甚至 long,破壞常量表達式資格。Y = 200 時 byte b2 = Y; 同樣報錯,驗證範圍檢查邏輯。Java 的隱式窄化轉換僅限於編譯期可確定值且不溢出的常量表達式。final 變量是否為常量表達式,取決於其初始化表達式;三元運算符的常量屬性取決於條件與分支是否均為常量。理解 JLS 15.28/15.25/5.2 規則,能避開 90% 的「明明在範圍內卻報錯」困惑。