
本文详解如何使用纯位运算(&、>>)将任意整数(支持 -524288 至 524287)准确转为十六进制字符串,修正原固定循环导致的高位截断问题,并妥善处理负数与零边界情况。
本文详解如何使用纯位运算(`&`、`>>`)将任意整数(支持 -524288 至 524287)准确转为十六进制字符串,修正原固定循环导致的高位截断问题,并妥善处理负数与零边界情况。
原始代码通过 for (int i = 0; i > 4 的 byte 强制转换会引发符号扩展与数据截断,导致高位丢失——这正是“最后两位正确、其余错误”的根本原因。
✅ 正确思路:以数值归零为循环终止条件
应摒弃固定次数循环,改用 while (v != 0) 动态提取每 4 位(即一个十六进制位)。同时必须移除 (byte) 强制类型转换,避免有符号截断;使用无符号右移逻辑(对负数需特殊处理)或统一采用补码视角的非负化策略。
但注意:Java 中 >> 是带符号右移,对负数会填充 1,导致无限循环(例如 -1 >> 4 永远为 -1)。因此,标准且健壮的位运算解法需将输入视为 32 位补码整数,并逐次处理低 4 位,再逻辑右移 4 位(等价于 >>> 4)。不过,题目限定范围为 -524288 至 524287(即 20 位有符号数),完全落在 int 安全范围内,我们可采用更直观的非负化预处理 + 无符号循环方案:
public static String decimalToHex(int v) {
if (v == 0) return "0"; // 特殊处理零
boolean negative = v < 0;
int num = negative ? -v : v; // 转为正数处理(注意:-Integer.MIN_VALUE 会溢出,但本题范围不涉及)
StringBuilder hex = new StringBuilder();
while (num > 0) {
int rem = num & 0xF; // 等价于 num % 16,取低 4 位
hex.insert(0, "0123456789ABCDEF".charAt(rem));
num >>>= 4; // 无符号右移 4 位(关键!避免负数陷阱)
}
return negative ? "-" + hex.toString() : hex.toString();
}? 为什么用 >>> 而非 >>?
>>> 是无符号右移,高位恒补 0,确保 num 单调递减至 0;而 >> 在 num 为负时会因符号扩展使值不变或更负,造成死循环。
⚠️ 关键注意事项
- 零值必须显式处理:否则 while (num > 0) 循环直接跳过,返回空字符串。
- 负数范围安全性:本题最大绝对值为 524287(0x7FFFF),其相反数 -524287 在 int 中完全可表示,-v 不会溢出(Integer.MIN_VALUE = -2147483648,远小于 -524287)。
-
效率与可读性:StringBuilder.insert(0, ...) 时间复杂度略高(O(n²)),生产环境推荐先追加再反转:
hex.append("0123456789ABCDEF".charAt(rem)); // 循环结束后: return negative ? "-" + hex.reverse().toString() : hex.reverse().toString(); - 不依赖内置方法:全程仅使用 &、>>>、字符串索引及基础控制流,严格符合题目约束。
✅ 验证示例
System.out.println(decimalToHex(13)); // "D" System.out.println(decimalToHex(256)); // "100" System.out.println(decimalToHex(-100)); // "-64" System.out.println(decimalToHex(524287)); // "7FFFF" System.out.println(decimalToHex(-524288)); // "-80000"
综上,核心在于用动态循环替代固定长度、用无符号右移保障收敛、并严谨覆盖零与负数边界。这一模式不仅解决当前需求,也为理解底层进制转换与位运算本质提供了坚实范例。









