Integer.toHexString(int num) 函数功能是将十进制数转化为16进制,并返回16进制String字符串。
不过,它的原理是怎样的呢? 我们今天来研究一下。
本文针对Java 8。
1. 查看下源码的函数说明
Returns a string representation of the integer argument as an unsigned integer in base 16.
The unsigned integer value is the argument plus 2^32 if the argument is negative; otherwise, it is equal to the argument. This value is converted to a string of ASCII digits in hexadecimal (base 16) with no extra leading 0s.
The value of the argument can be recovered from the returned string s by calling Integer.parseUnsignedInt(s, 16).
If the unsigned magnitude is zero, it is represented by a single zero character '0' ('u0030'); otherwise, the first character of the representation of the unsigned magnitude will not be the zero character. The following characters are used as hexadecimal digits:
0123456789abcdef
These are the characters 'u0030' through 'u0039' and 'u0061' through 'u0066'. If uppercase letters are desired, the String.toUpperCase() method may be called on the result:
Integer.toHexString(n).toUpperCase()
意思是说:
返回一个integer类型参数num所代表的无符号integer对应的16进制数的字符串。
如果num < 0,则无符号integer值+232(符号位由0变为1);如果num>=0,则无符号integer值 = num。 然后,这个无符号值转换成一个以16进制形式的ASCII数字的字符串
参数值num能通过调用Integer.parseUnsignedInt(s, 16)从返回的string进行恢复。
如果无符号数值是0,那么它通过单个0字符 '0'('u0030')来表示;否则,无符号数值16进制字符串首字母不会是0。后面的字符使用16进制数字:
0123456789abcdef
对应Unicode编码0~9: 'u0030'~'u0039'; a~f: 'u0061'~'u0066'。
如果想用大写字母,可以使用String.toUpperCase() 转换结果:
Integer.toHexString(n).toUpperCase()
2. 查看Integer.java中toHexString原型
只有一个简单调用
public static String toHexString(int i) {
return toUnsignedString0(i, 4);
}
继续查看toUnsignedString0原型:
/**
* Convert the integer to an unsigned number.
*/
private static String toUnsignedString0(int val, int shift) {
// assert shift > 0 && shift <=5 : "Illegal shift value";
int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val); // 得出val所占用二进制数的位数
int chars = Math.max(((mag + (shift - 1)) / shift), 1); // 要转换成的String 缓冲区字符个数, 最少为1. 一般地,当mag == 4的倍数时,缓冲器个数=mag/4;当mag % 4不为0时,多余4的倍数部分也会占用一个额外的空间
char[] buf = new char[chars]; // 申请存储shift对应进制的字符缓冲区
formatUnsignedInt(val, shift, buf, 0, chars); // 将val值,按shift对应进制,转换成字符,存储进buf缓冲区
// Use special constructor which takes over "buf".
return new String(buf, true); // 将char缓冲区结果转换为String
}
继续查看numberOfLeadingZeros和formatUnsignedInt
numberOfLeadingZeros 返回i对应二进制数,从左边开始连续0的个数;
formatUnsignedInt
/**
* Returns the number of zero bits preceding the highest-order
* ("leftmost") one-bit in the two's complement binary representation
* of the specified {@code int} value. Returns 32 if the
* specified value has no one-bits in its two's complement representation,
* in other words if it is equal to zero.
*
* @param i the value whose number of leading zeros is to be computed
* @return the number of zero bits preceding the highest-order
* ("leftmost") one-bit in the two's complement binary representation
* of the specified {@code int} value, or 32 if the value
* is equal to zero.
*/
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;
}
/**
* 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;
int radix = 1 << shift; // 将shift转化成进制数值,shift=4 代表16进制(radix=16)
int mask = radix - 1; // radix进制下最大值,也是各位全1的mask
// 从缓冲区末尾向头部填充数据
do {
buf[offset + --charPos] = Integer.digits[val & mask]; // 将val对应16进制字符,填充进buf数组。这里由于val与mask进行了& 位运算,结果不可能超过mask,也就是说如果16进制只会对应索引为0~15的digits数
val >>>= shift; // 将val无符号右移shift位
} while (val != 0 && charPos > 0); // 最终循环退出条件要么为val = 0,要么是charPos = 0。通常是2者同时到0
return charPos;
}
查看Integer.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'
};