
本文深入解析 Java 中 long & int 运算时因整数字面量默认为 int 类型,导致数值提升与符号扩展引发的“意外结果”,并提供正确使用 0xFFFFFFFFL 等长整型字面量的实践方案。
本文深入解析 java 中 long & int 运算时因整数字面量默认为 int 类型,导致数值提升与符号扩展引发的“意外结果”,并提供正确使用 0xffffffffl 等长整型字面量的实践方案。
在 Java 中,按位与运算符 & 是基础但极易被误解的操作符之一。看似简单的表达式 a & 0xFFFFFFFF,在 a 为 long 类型时,却可能产生与预期完全不符的结果——这并非 JVM 错误,而是 Java 类型系统严格遵循规范所导致的可预测但易忽略的行为。
? 问题本质:字面量类型 + 数值提升 + 符号扩展
在您的示例中:
long a = -26000;
System.out.printf("%X\n", a); // FFFFFFFFFFFFF9A70(-26000 的 64 位补码)
System.out.printf("%X\n", (a & 0xFFFFFFFF)); // ❌ 仍为 FFFFFFFFFFFFF9A70
System.out.printf("%X\n", (a & 0x00000000FFFFFFFF)); // ❌ 同样是 FFFFFFFFFFFFF9A70关键在于:0xFFFFFFFF 和 0x00000000FFFFFFFF 在 Java 中均为 int 字面量(32 位有符号整数),其十进制值为 -1(因为 0xFFFFFFFF 是 int 范围内最大的负数补码表示)。
当 long 与 int 进行 & 运算时,Java 执行 widening primitive conversion(宽化原始类型转换):
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
int值-1(即0xFFFFFFFF)被提升为long; - 提升过程采用符号扩展(sign extension):高位全部填充原符号位(
1),因此-1→0xFFFFFFFFFFFFFFFF(64 位全 1); - 最终计算变为:
a & 0xFFFFFFFFFFFFFFFF,等价于a & (-1),结果恒为a自身。
这就是为何三行输出完全一致的根本原因。
✅ 正确写法:显式声明 long 字面量
要真正实现「只保留低 32 位,高位清零」的掩码效果,必须让掩码本身是 long 类型,避免符号扩展:
long a = -26000;
System.out.printf("%X\n", a); // FFFFFFFFFFFFF9A70
System.out.printf("%X\n", (a & 0xFFFFFFFFL)); // ✅ 9A70(低 32 位)
System.out.printf("%X\n", (a & 0x00000000FFFFFFFFL)); // ✅ 同样是 9A70添加 L(或 l)后缀后,0xFFFFFFFFL 成为 long 字面量,其值为 4294967295(无符号 32 位最大值),二进制为 0x00000000FFFFFFFF(64 位)。此时 a & 0xFFFFFFFFL 才真正执行「按位与」,将 a 的高 32 位清零,仅保留低 32 位有效数据。
? 小贴士:
0xFFFFFFFFL是最常用且可读性最佳的写法;0x00000000FFFFFFFFL虽语义更明确,但冗余,不推荐日常使用。
⚠️ 注意事项与最佳实践
-
永远检查字面量类型:Java 中十六进制/十进制字面量若未加
L/l,默认为int;八进制字面量同理。 -
避免魔法数字:建议用常量替代硬编码掩码,增强可维护性:
private static final long LOWER_32_BITS = 0xFFFFFFFFL; long masked = a & LOWER_32_BITS;
-
对比其他语言差异:C# 中
0xFFFFFFFF在long上下文中会自动推导为uint或ulong(取决于上下文),而 Java 无此行为,必须显式后缀。 -
扩展思考:该规则同样适用于
, <code>>>,|,^等所有位运算——只要操作数类型不同,就触发数值提升与符号扩展。
掌握这一机制,不仅能解决“输出异常”的困惑,更能写出跨平台、可移植、无歧义的底层位操作代码。位运算是性能敏感场景(如网络协议解析、加密算法、哈希实现)的基石,而对类型的精确控制,正是专业级 Java 开发者的必备素养。

















