public static String toHexString(int i) {
return toUnsignedString0(i, 4);
}
底层方法实际上是一个二进制、八进制和十六进制通用的一个方法
/**
* Convert the integer to an unsigned number.
*/
private static String toUnsignedString0(int val, int shift) {
// assert shift > 0 && shift <=5 : "Illegal shift value";
//通过Integer最大的长度减去开头0的个数,计算输入的数值真正占的位数
int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val);
//计算真正占用的位转换后,所占用的位数
int chars = Math.max(((mag + (shift - 1)) / shift), 1);
//根据计算得出的长度创建一个最终返回的char[]数组
char[] buf = new char[chars];
//算是真正的将Integer类型转换成需要进制的方法
formatUnsignedInt(val, shift, buf, 0, chars);
//使用char[]数组创建一个String类型返回
// Use special constructor which takes over "buf".
return new String(buf, true);
}
参数:
- val:想要转换的Integer值
- shift:转换的位数,二进制:1;八进制:3;十六进制:4
步骤具体详解
1、计算最前面站位0的个数
public static int numberOfLeadingZeros(int i) {
// HD, Figure 5-6
if (i == 0)
return 32;
int n = 1;
if (i >>> 16 == 0) { n += 16; i <<= 16; }
if (i >>> 24 == 0) { n += 8; i <<= 8; }
if (i >>> 28 == 0) { n += 4; i <<= 4; }
if (i >>> 30 == 0) { n += 2; i <<= 2; }
n -= i >>> 31;
return n;
}
2、获取转换后占用的长度
//计算真正占用的位转换后,所占用的位数
int chars = Math.max(((mag + (shift - 1)) / shift), 1);
a、shift - 1的作用:将位数向上取整
例:
//如果真正的长度为6,转换成十六进制,不加(shift - 1)时
6/4 = 1
//小数部分被省略了,但其实我们需要两位来装长度为六的数据
//添加了(shift - 1)后
(6+(4-1))/4 = 2
//就将计算结果向上取整
b、Math.max(int a, int b);比较最大值
3、真正的转换方法
/**
* Format a long (treated as unsigned) into a character buffer.
* @param val the unsigned int to format
* @param shift the log2 of the base to format in (4 for hex, 3 for octal, 1 for binary)
* @param buf the character buffer to write to
* @param offset the offset in the destination buffer to start at
* @param len the number of characters to write
* @return the lowest character location used
*/
static int formatUnsignedInt(int val, int shift, char[] buf, int offset, int len) {
//将长度赋值给一个新的变量
int charPos = len;
//获取基数,二进制为2,八进制为8,十六进制为16
int radix = 1 << shift;
//根据基数获取当前进制的最大数,用于格式化。二进制:0b1,八进制:0777,十六进制:0xFFFF
int mask = radix - 1;
//进行循环将内容添加进char[]数组
do {
//将Integer的最低四位根据最大值格式化,然后根据格式化的值去上面的char[]数组中取值,
//再将取到的char按照倒叙存入目标数组buf中
buf[offset + --charPos] = Integer.digits[val & mask];
//无符号右移进制的个数
val >>>= shift;
//判断当前val是否为0并且存写长度是否为零,如果val不为零且存写长度也不为0,继续循环
} while (val != 0 && charPos > 0);
//返回剩余的存写长度
return charPos;
}
参数
- val:需要转换的Integer类型值
- shift:几位转换成一个,二进制:1;八进制:3;十六进制:4;
- buf:目标数组,转换后的数据存储的地方
- offset:偏移量,从buf存储的偏移量
- len:存写的长度
a、digits数组
/**
* All possible chars for representing a number as a String
*/
final static char[] digits = {
'0' , '1' , '2' , '3' , '4' , '5' ,
'6' , '7' , '8' , '9' , 'a' , 'b' ,
'c' , 'd' , 'e' , 'f' , 'g' , 'h' ,
'i' , 'j' , 'k' , 'l' , 'm' , 'n' ,
'o' , 'p' , 'q' , 'r' , 's' , 't' ,
'u' , 'v' , 'w' , 'x' , 'y' , 'z'
};
4、创建字符串类型返回
return new String(buf, true);
- 所使用的构造方法的访问级别为缺省,包下访问
- value:表示需要转换的char[]数组
- share:标识符号,为了和常用的公共的构造器(如下图)区分开,值常为true
- 方法直接将char[]数组的引用赋值给value,
好处
- 和公共方法的Arrays.copyOf()比,速度更快
缺点
- 因为是直接将引用赋值给value,所以当char[]数组改变时,String的内容也会一同改变,不符合String一旦创建就不能改变的原则,所以为访问修饰符为缺省
总结
本质上toHexString方法,其实就是根据要转换的位数变成脚标,然后去一个特定的数组中取数,然后封装成String返回
buf[offset + --charPos] = Integer.digits[val & mask];
其他的所有代码都是为这个做准备
本文详细解析了Java中整型转化为十六进制的底层实现过程,包括计算前导零个数、确定转换后长度及核心转换方法。通过具体步骤与代码示例,帮助读者理解toHexString方法的工作原理。

被折叠的 条评论
为什么被折叠?



