Java Object 通用方法 toString() 之 Integer.toHexString()

toString()的源代码如下:

public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

getClass() 返回类对象 ;

getName() 以String形式返回类对象的名称(包换包名);

Integer.toHexString(hashCode()) 以对象的哈希码为参数,以16进制无符号整数形式返回此哈希码的字符串表示形式;

下面主要分析下Integer.toHexString()

以下是其源码:

public static String toHexString(int i) {
    return toUnsignedString0(i, 4);
}
private static String toUnsignedString0(int val, int shift) {
    // assert shift > 0 && shift <=5 : "Illegal shift value";
    int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val); 	// (1)
    int chars = Math.max(((mag + (shift - 1)) / shift), 1);		// (2)
    char[] buf = new char[chars];

    formatUnsignedInt(val, shift, buf, 0, chars);			// (3)

    // Use special constructor which takes over "buf".
    return new String(buf, true);
}

(1) 这一步主要是为了计算val值对应的二进制数中除去首部0的个数后剩下的有效位数mag。

    a.Integer.SIZE: int在jvm中占4个字节,共32位;

    b.首部0的个数:是指从左边第一个位置开始累加0的个数,一直加到第一个非零值;

    c.方法numberOfLeadingZeros() 就是计算首部0的个数。

下面看看numberOfLeadingZeros()的源码,源码应用了二分查找,先把32位整形分为高16位和低16位查找非零数,在对高16位进行或低16位进行二分,以此类推,直到找到左边第一个非零值的位置。

public static int numberOfLeadingZeros(int i) {
    // HD, Figure 5-6
    if (i == 0)
        return 32;
    // 初始首部0的个数:1 假定最高位有一个0,最后的时候会根据最高位是否位零补偿返回
    int n = 1;
    // 下面的代码主要是为了找出左边第一个非零值的位置
    // 采用二分查找的方法,首先将 i 无符号右移16位后,有两种情况(a, b):
    // a. 右移后 = 0,则第一个非零值出现在低16位,那么 i 首位至少有16个0(n=17),
    // 同时将 i 左移16位后赋值给自己(将低16位移到了高16位,这样可以使两种保持同一的状态进行后续判断);
    // b. 右移后!=0,则第一个非零值出现在高16位(n=1),继续在高16位中寻找;
    // 将高16位继续分为 高8位和低8位进行判断,一直二分到还有两位的时候;
    // 最后 i 无符号右移31位(结果要么是0要么是1),如果右移后为0,说明此时的最高位为0,无需补偿,直接返回 n;
    // 如果右移后是1,则说明最高位不为0,需补偿,返回 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):计算 i 的有效二进制的位数所需要占的字符数(即对应的16进制的有效位数),toString()方法是以16进制返回,这里就以16进制来解释。

根据二进制和16进制的转化关系可以知道,每4个二进制位代表一个16进制数,mag是有效的二进制位个数,所以想要计算需要的字符数可能遇到如下三种情况:

   a. mag=0,那么只需要一个字符即可;
   b. mag !=0, 是4的整数倍,则需要mag/4 个字符;
   c. mag !=0,不是4的整数倍,则需要mag/4 +1 个字符;

(mag + (shift - 1)) / shift 可以解决后面两种情况;

Math.max(((mag + (shift - 1)) / shift), 1) 可以解决这三种情况。

(3) 在toString() 方法中,formatUnsignedInt() 完成的功能就是将val值以16进制数形式存进buf数组中。

先进行按位与运算,算出val的二进制中低四位对应的10进制的值,在 digits 数组中获取对应的16进制值,存进buf字符数组中;后将val无符号右移4位,保持在最低四位与mask进行按位与运算,在 digits 数组中获取对应的16进制值,存进buf字符数组中,以此循环,直到val=0或者charPos<=0后退出循环。

     static int formatUnsignedInt(int val, int shift, char[] buf, int offset, int len) {
        int charPos = len;
        int radix = 1 << shift;
        int mask = radix - 1;
        do {
            buf[offset + --charPos] = Integer.digits[val & mask];
            val >>>= shift;
        } while (val != 0 && charPos > 0);

        return charPos;
    }

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

由代码可见,digits 数组中表示 16 进制的是前 16 个,数组下标最大为 15, Integer.digits[val & mask] 保证了每次从最低四位开始匹配对应的 16 进制数。

总的来说,分为了如下步骤:

(1)计算 hashCode 对应的有效二进制位数 n

(2)n 位二进制数对应的 16 进制数的个数,即对应的所要占据的字符数

(3)将 n 位二进制数转换为 16 进制数并存入字符数组中

(4)最后返回 16 进制无符号整数的字符串

如有疑问,欢迎沟通~

 


 

 

 

 


 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值