• 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

  • 相关阅读:
    服务上线怎么兼容旧版本?
    abstract class和interface有什么区别?
    Anonymous Inner Class (匿名内部类)是否可以extends(继承)其它类,是否可以implements(实现)interface(接口)?
    寒假每日日报49(开发家庭记账本APP——进度十)
    寒假每周总结7
    寒假每日日报48(开发家庭记账本APP——进度九)
    寒假每日日报47(开发家庭记账本APP——进度八)
    寒假每日日报46(开发家庭记账本APP——进度七)
    寒假每日日报45(开发家庭记账本APP——进度六)
    寒假每日日报44(开发家庭记账本APP——进度五)
  • 原文地址:https://www.cnblogs.com/fortunely/p/14150969.html
Copyright © 2020-2023  润新知