Java Study--Interger.toString(int i)(10进制数版本)

源码

 public static String toString(int i) {
        if (i == Integer.MIN_VALUE)
            return "-2147483648";

        // BEGIN Android-changed: Cache the String for small values.
        // int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
        // 注意这里的BEGIN Android-changed和 END Android-changed 注释
        // 在AndroidStudio中读源码有这一段
        // 在Intellij中读到的源码是没有BEGIN和END之间的这一段代码的,
        // 个人理解,不太恰当的比喻下就是android的jre和传统Java开发的jre不一样。
        // 这个方法在不同运行环境下的真正实现不一样
        boolean negative = i < 0;
        boolean small = negative ? i > -100 : i < 100;
        
        // 判断值在区间(-100,100),采用类似缓存机制的方式来读取
        if (small) {
        	// SMALL_NEG_VALUES 和 SMALL_NONNEG_VALUES 分别是(-100,0)和 [0,100)两个区间正数对应字符串的缓存池
        	// 以私有静态常量数组的形式被声明在Integer中,随着Integer的初始化而初始化,初始情况下为空,长度为100
        	
            final String[] smallValues = negative ? SMALL_NEG_VALUES : SMALL_NONNEG_VALUES;

            if (negative) {
            	// 在值为负数的情况下,将其视作正数来进行处理
                i = -i;
                // 在smallValues数组中直接根据 i 作为索引查询字符串
                if (smallValues[i] == null) {
                	// DigitOnes和DigitTens 是两个静态常量数组,值已经写入好了,长度为100
                	// 内容是位于区间 [0,99]的100个数,按照从0到99的顺序,分别对应的个位数的字符和十位数的字符
                    smallValues[i] =
                    	// 如果小于10,直接赋值smallValues[i]  ‘-’+(查询得到的个位数对应字符)
                        i < 10 ? new String(new char[]{'-', DigitOnes[i]})
                        		// 否则赋值smallValues[i]  ‘-’+(十位数字符+个位数字符)
                               : new String(new char[]{'-', DigitTens[i], DigitOnes[i]});
                     	// 如果仅采用三元表达式 末尾 十+个 的方式,会给小于10的数字符补上0,所以不对
                }
            } else {
            	// 大概原理同上
                if (smallValues[i] == null) {
                    smallValues[i] =
                        i < 10 ? new String(new char[]{DigitOnes[i]})
                               : new String(new char[]{DigitTens[i], DigitOnes[i]});
                }
            }
            // 位于(-100,100)区间的数,经过上述代码块,已经在smallValue对应的缓存数组中生成或查询到了值
            // 直接按照索引返回即可
            return smallValues[i];
        }
        // 对于位于(-∞,-100]和区间[100,∞)的数,先计算位数
        int size = negative ? stringSize(-i) + 1 : stringSize(i);
        // stringSize(i)方法用于计算数字的位数
        //如果是负数还要留出一位符号位
        // END Android-changed: Cache the String for small values.
        char[] buf = new char[size]; // 生成对应位数的char数组
        getChars(i, size, buf); // getChars(...)方法将每一位对应的char放入数组
        // Android-changed: Use regular constructor instead of one which takes over "buf".
        // return new String(buf, true);
        return new String(buf); // 返回char数组组成的字符串
    }

getChars(int i, int index, char[] buf)方法

static void getChars(int i, int index, char[] buf) {
        int q, r;
        int charPos = index;
        char sign = 0;

        if (i < 0) {
        	// 负数全部当作正数处理
        	// 并单独记录符号为sign
            sign = '-';
            i = -i;
        }

        // Generate two digits per iteration
        // 当值大于65536时,每次循环,生成2位字符
        // iEg=1165536,buf=[ , , , , , , ] charPos=7
        while (i >= 65536) {
            q = i / 100; // q记录了下次循环时i 对应的初始数
            // qEg=11655,则本次应该写入‘3’,‘6’
        // really: r = i - (q * 100); 
            r = i - ((q << 6) + (q << 5) + (q << 2));  
            // (q<<6)+(q<<5)+(q<<2)==q*2^6+q*2^5+q*2^2==q*(64+32+4)==q*100
            // 采用左移的方式相比直接*100,在纳秒级别可以看出,左移会明显快很多。毫秒级别可能看不太清楚。
            // r= i-(q*100) ==i-((i/100)*100)==i Mod(100) 既是该次应该写入的两位字符对应的值
            // rEg=36
            i = q;
            buf [--charPos] = DigitOnes[r]; // 利用之前的DigitOnes和DigitTens
            buf [--charPos] = DigitTens[r];
            // bufEg=[ , , , , ,'3','6'] charPosEg=5,iEg=11655,下一轮会跳出循环
        }
		
		// iEg=11655
		// 前面将 从第0位到第3位的数记录到了buf中
        // Fall thru to fast mode for smaller numbers
        // assert(i <= 65536, i);
        for (;;) {
            q = (i * 52429) >>> (16+3);
            // 2^19=524288
            // q=( i* ((2^19+2)/10))  / 2^19 == i/10 ((2^19+2)/2^19 是int除int 在 jvm中计算结果为1)
            // 但是为什么要写成 16+3?表示+3是精心选择过的意义吗?意义又在哪?
            // 前面为什么又要选65536=2^16,选这几个数的道理是什么?没搞懂。
            // qEg=1165
            r = i - ((q << 3) + (q << 1));  // r = i-(q*10) ...
            // 同上 r=i-q*(2^3+2)
            // rEg=11655-1165*10=5
            buf [--charPos] = digits [r];
           	// digits[]是一个36位char数组,内容为‘0’~‘9’,‘a’~'z'
           	// 在大于10进制的进制的toString中还会用到,所以有后面的'a'~'z'
           	// 此时buf=[ , , , ,5,3,6],charPosEg=4
            i = q;
            // iEg=1165,之后循环直到 i==0
            if (i == 0) break;
        }
        if (sign != 0) {
        	// 如果存在符号'-',则在第一位放入符号
            buf [--charPos] = sign;
        }
    }

stringSize方法,原理一看便知,不再赘述。

final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
                                      99999999, 999999999, Integer.MAX_VALUE };

    // Requires positive x
    static int stringSize(int x) {
        for (int i=0; ; i++)
            if (x <= sizeTable[i])
                return i+1;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值