Java源码解析:Integer.toHexString

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'
    };

练习题目
405. 数字转换为十六进制数 | LeetCode

posted @ 2020-12-17 19:44  明明1109  阅读(2887)  评论(0编辑  收藏  举报