尊重原创,转载请标明出处    http://blog.csdn.net/abcdef314159

对于Integer这个类估计大家也都非常熟悉了,以前看过他的源码,但也只是粗略的看了一下,最近有时间认真的看了一下发现这个类设计的非常好,所以就打算记录下来与大家共享。我们看一下java项目中的Integer类大概有500多行,并且注释也很少,

而Android中的Integer大概有1000多行,当然他的注释也比较多

既然是要分析,那么就索性两个一起来分析,这里我以Android中的Integer为主,是挑着来分析的,不是按顺序的,先看一下bitCount(int i)这个方法

    /*** Returns the number of one-bits in the two's complement binary* representation of the specified {@code int} value.  This function is* sometimes referred to as the <i>population count</i>.** @return the number of one-bits in the two's complement binary*     representation of the specified {@code int} value.* @since 1.5*/public static int bitCount(int i) {// HD, Figure 5-2i = i - ((i >>> 1) & 0x55555555);i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);i = (i + (i >>> 4)) & 0x0f0f0f0f;i = i + (i >>> 8);i = i + (i >>> 16);return i & 0x3f;}

他表示的是计算int类型转化为二进制之后1的个数,举个例子,5用二进制表示为101,那么就返回2,表示有2个1,8用二进制表示是1000,就会返回1,表示有一个1.但是这个方法用的非常妙,直接看可能不是太明白,如果把上面的数字转化成二进制可能就会明白很多,0x55555555用二进制表示就是……01010101(1个0,1个1循环,总共是32位),0x33333333用二进制表示就是……00110011(2个0,2个1循环,总共32位),0x0f0f0f0f用二进制表示就是……0000111100001111(4个0,4个1循环,总共32位),看到这里可能就会稍微有点明白,其实他的原理就是每两位为一个小的单元,计算出1的个数储存在两位数中,然后再以4位为一个小的单元计算前面储存的数的和,储存到4位数中,然后再以8位,16位,以此类推。但这里要注意第一行和后面的几行原理是不同的,第一行是计算1的个数,后面的几行都是对第一行计算的结果相加,举个例子,比如第一行开始计算的时候如果最后两位二进制数为10,那么他表示最后两位只有一个1,因为还一个为0,如果是后面的几行,那么开始计算的时候如果二进制为10,那么他表示最后两位数有2个1,因为从第二行开始每个位上的1和0不在是表示1和0了,他表示的是第一行1和0的个数的和,而二进制10就是十进制2的意思,所以他表示的是2个1。其实第一行很好理解,i往右移动一个单位,再与……01010101(32位)进行与运算,就表示把原来的偶数位变为奇数位,然后再把新的偶数位置为0,再用i减去他,他表示的是把一个数每两个分为一组,然后让每组中的数减去这个组的偶数位上的数字,所以他最终表示的结果就是每两位1的个数储存在原来的两位数中,我画个图就好理解了

我还是写在代码里逐行分析可能会更好一些,下面是代码的分析

    public static int bitCount(int i) {// HD, Figure 5-2/*** 每两位为一个单元,把原来单元中1的个数储存在原来的单元中*/i = i - ((i >>> 1) & 0x55555555);/***0x33333333其实就是二进制……00110011(共32位),因为上面的每两位代表1的个数,所以下面的这几行就是要把上面每两位* 的数字加起来,下面的这行代码可以这样理解,每4位分为一组,然后4位中的每两位相加,相加的结果在储存到这4位二进制数中,* i & 0x33333333表示每4位中的低2位,(i >>> 2) & 0x33333333表示每4位中的高2位,然后在相加*/i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);/*** 这个更好理解,i >>> 4表示往右移动了4位,然后在与i相加,相当于每8位一组,然后8位中的高4位与低4位相加储存在低4位中,* 然后这里在与0x0f0f0f0f进行与运算,把高4位完全置为0了,因为0x0f0f0f0f用二进制表示就是00001111000011110000111100001111,* 看到这里可能有些困惑,这里为什么要与0x0f0f0f0f进行与运算,因为每8位一组的话,最多也就是8,那么4位数足够了,高4位就没有必要了,* 如果不置为0有没有影响,其实如果1的位数极少的话是没什么影响的,但如果1的位数比较多到后面计算的结果可能就会往前进位,导致结果错误,* 所以这一步要进行一次与运算,那为什么上面的那行代码没有把4位一组中的高两位置0,这是因为4位一组最多有4个1,而2位二进制数最多表示3,* 小于4,所以不能置为0,**/i = (i + (i >>> 4)) & 0x0f0f0f0f;/*** 和上面类似,每16位分为一组,每组中的高8位和低8位相加,这里的代码相加的很干净,因为无论是高8位还是低8位中的前4位在上面一行中* 都已经置为0了,这里也可以像上面那样,加完之后在与0x00ff00ff进行与运算,但其实这里已经没有必要了,因为int类型为32位,* 最多也就32个1,用8位数储存足够了,所以不会超过8位,也就不用担心超过8位在往前进1位的问题了。*/i = i + (i >>> 8);/*** 和上面类似,就不在详述*/i = i + (i >>> 16);/*** 到最后为什么要和0x3f进行与运算,0x3f用二进制表示就是111111,因为上面两行没有进行与运算,所以前面的数据都是无效的,* 只有最后8位是有效的,而后8位的前两位不用说肯定为0,因为最多也就32个1,用后面6位数表示就已经足够了,所以这里与0x3f* 进行与运算,来计算出最终1的个数*/return i & 0x3f;}

再来看一下java中的bitCount(int var0)的方法

    public static int bitCount(int var0) {var0 -= var0 >>> 1 & 1431655765;var0 = (var0 & 858993459) + (var0 >>> 2 & 858993459);var0 = var0 + (var0 >>> 4) & 252645135;var0 += var0 >>> 8;var0 += var0 >>> 16;return var0 & 63;}

其实他和Android中的bitCount是一样的,只不过他是10进制,而Android中的是16进制。我们再来看Android中的下一个方法

    /*** Returns an {@code int} value with at most a single one-bit, in the* position of the highest-order ("leftmost") one-bit in the specified* {@code int} value.  Returns zero if the specified value has no* one-bits in its two's complement binary representation, that is, if it* is equal to zero.** @return an {@code int} value with a single one-bit, in the position*     of the highest-order one-bit in the specified value, or zero if*     the specified value is itself equal to zero.* @since 1.5*/public static int highestOneBit(int i) {// HD, Figure 3-1i |= (i >>  1);i |= (i >>  2);i |= (i >>  4);i |= (i >>  8);i |= (i >> 16);return i - (i >>> 1);}

他表示的就是从左往右数,遇到第一个1保留,则其之后的所有全部清零,我可以这样来理解,就是小于或等于这个数的最大的2的n次方,当i等于2的n次方的时候,结果还是等于i,当i不是2的n次方的时候就会返回小于i的最大的2的n次方,举个例子,如果i是8则返回8,因为8是2的3次方,如果i是31,则返回16,因为2的4次方是16小于31,而2的5次方是32,大于31,所以32不合适。说到这里,自然会联想到之前写的Android HashMap源码详解中讲到的roundUpToPowerOfTwo(int i)方法,而roundUpToPowerOfTwo方法返回的是大于或等于i的最小的2的n次方。highestOneBit的原理其实很简单,他就是通过左边遇到第一个1然后不停的右移然后在进行与运算,把1后面全部置为1,最后一步在通过i - (i >>> 1)把左边第一个1之后的全部置为0,这个可以参照一下roundUpToPowerOfTwo的原理图,大家可以这样理解,当i是2的n次方的时候highestOneBit函数和roundUpToPowerOfTwo函数返回的结果是一样的,当i不是2的n次方的时候,roundUpToPowerOfTwo返回的结果是highestOneBit的2倍。其实讲到这就已经基本上结束了,但由于好奇又看了一下HashMap中初始化数组大小的方法,发现又变了,不得不感慨Android的源码变化实在是太快了,这次看的是Android-25的,代码如下

    private static int roundUpToPowerOf2(int number) {// assert number >= 0 : "number must be non-negative";int rounded = number >= MAXIMUM_CAPACITY? MAXIMUM_CAPACITY: (rounded = Integer.highestOneBit(number)) != 0? (Integer.bitCount(number) > 1) ? rounded << 1 : rounded: 1;return rounded;}

我们看到他已经换成Integer的highestOneBit方法了,我们看到有这样一段代码(Integer.bitCount(number) > 1),他表示number是不是2的n次方,如果是就返回rounded,如果不是就返回rounded<<1,因为我们知道highestOneBit是返回小于或等于number的最大的2的n次方,而HashMap初始化的大小是不能小于number的,所以当number为2的n次方的时候直接返回,当number不为2的n次方的时候就会返回rounded的2倍。而java中的highestOneBit和Android中的highestOneBit方法基本类似,这里就不在贴出,下面再来看下一个方法,

    /*** Returns the value obtained by reversing the order of the bits in the* two's complement binary representation of the specified {@code int}* value.** @return the value obtained by reversing order of the bits in the*     specified {@code int} value.* @since 1.5*/public static int reverse(int i) {// HD, Figure 7-1i = (i & 0x55555555) << 1 | (i >>> 1) & 0x55555555;i = (i & 0x33333333) << 2 | (i >>> 2) & 0x33333333;i = (i & 0x0f0f0f0f) << 4 | (i >>> 4) & 0x0f0f0f0f;i = (i << 24) | ((i & 0xff00) << 8) |((i >>> 8) & 0xff00) | (i >>> 24);return i;}

他表示把i转化为二进制数,然后再把这个二进制数反转,只要把上面的16进制数转化为二进制就一目了然了,我们先来看一下字母的反转,再来分析上面的就容易多了

看完这个图之后,那么上面的代码就非常容易理解了,先看第一行(i & 0x55555555) << 1 | (i >>> 1) & 0x55555555;先把0x55555555转化为二进制,会发现(i & 0x55555555) << 1表示把i的偶数为置0,奇数位不变,然后在左移,把原来的奇数位变成了现在的偶数位,而原来的偶数位变为现在的奇数位,然后全部置为0了,(i >>> 1) & 0x55555555右移一位,把原来的偶数为变为奇数位了,然后在与0x55555555进行与运算,相当于把原来的奇数位放到现在的偶数位上,然后全部置为0,原来的偶数位不变然后放到现在的奇数位上,最后来一个|(或)运算,就相当于把原来的奇偶位交换了。而(i & 0x33333333) << 2 | (i >>> 2) & 0x33333333表示每4个一组,然后每组的前后两个进行交换,同理(i & 0x0f0f0f0f) << 4 | (i >>> 4) & 0x0f0f0f0f表示每8个一组,然后每组的前4个和后4个进行交换。关键来看最后一行(i << 24) | ((i & 0xff00) << 8) |((i >>> 8) & 0xff00) | (i >>> 24),因为前面已经交换到每8个一组了,所以到这里也是每8个分为一组,下面还是画个图来理解一下吧

OK,下面再来看下一个方法

    /*** Returns the value obtained by reversing the order of the bytes in the* two's complement representation of the specified {@code int} value.** @return the value obtained by reversing the bytes in the specified*     {@code int} value.* @since 1.5*/public static int reverseBytes(int i) {return ((i >>> 24)           ) |((i >>   8) &   0xFF00) |((i <<   8) & 0xFF0000) |((i << 24));}

这个和上面分析的i = (i << 24) | ((i & 0xff00) << 8) |((i >>> 8) & 0xff00) | (i >>> 24);其实是一样的,他表示反转字节,因为每个字节占8位,所以每次移动8位。接着往下看

    /*** Returns the number of zero bits following the lowest-order ("rightmost")* 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.** @return the number of zero bits following the lowest-order ("rightmost")*     one-bit in the two's complement binary representation of the*     specified {@code int} value, or 32 if the value is equal*     to zero.* @since 1.5*/public static int numberOfTrailingZeros(int i) {// HD, Figure 5-14int y;if (i == 0) return 32;int n = 31;y = i <<16; if (y != 0) { n = n -16; i = y; }y = i << 8; if (y != 0) { n = n - 8; i = y; }y = i << 4; if (y != 0) { n = n - 4; i = y; }y = i << 2; if (y != 0) { n = n - 2; i = y; }return n - ((i << 1) >>> 31);}

他表示返回从右边数第一个1右边0的个数,如果i是12,则返回2,因为12的二进制是1100,右边有2个0,如果i是0,则返回32,还是在代码里分析效果要好一些

    public static int numberOfTrailingZeros(int i) {// HD, Figure 5-14int y;//等于0的时候返回32if (i == 0) return 32;//因为返回的是右边第一个1的右边的0的个数,如果不是0,则0的个数肯定不会大于31int n = 31;/***  左移16位,如果y==0,说明原来i的低16位上是没有1的,只能说明高16位上有1,那么n肯定是大于或等于16。*  如果y!=0,说明原来i的低16位上肯定是有1,那么n就会小于16,只需要运算低16就行了,所以就把y赋值给i,*  同时n也要减去16,*/y = i <<16; if (y != 0) { n = n -16; i = y; }//同上y = i << 8; if (y != 0) { n = n - 8; i = y; }//同上y = i << 4; if (y != 0) { n = n - 4; i = y; }//同上y = i << 2; if (y != 0) { n = n - 2; i = y; }/*** (i << 1) >>> 31表示计算i的第31位上的值,i << 1表示把i的第31位变成32位,然后再无符号的右移31位,所以得到的结果就是i的第31位上的值,但是要记住这个i不是最初的那个i,而是运算之后的i,因为上面有赋值,当满足条件的时候i就会改变。这里为什么要减去第31位上的值,这是因为上面最后一行运行之前其实i已经判断了(16+8+4=28)位了,当上面最后一行运行之后就只剩下最后两位了,我们知道通过上面一步步的运算,到这里i的第32位和31位至少有1个1,不可能全是0,如果全是0只有当最初始的i为0的时候,那么这是不可能的,因为如果最初始的i为0,在最上面就已经被拦截了,直接返回32了。这里为什么要减去31位上的值而不是32位上的值,这就是算法的巧妙之处,因为这个方法返回的是右边第一个1右边0的个数,所以这里只需要判断第31位就行了,因为如果31位为1的话,那么32位就没他什么事了,不管他是0还是1都不会有影响,因为31位是在32位的右边(最右边是第一位,最左边是第32位),只需要把31位的1减掉就行了,如果31位是0,那么32位肯定为1,因为31和32位必须有一个是1,,其实他这里是把代码简化了,还可以这样写,把最后一行注释掉,改为下面这样,运算结果是一样的// y = i << 1; if (y != 0) { n = n - 1; }// return n ;*/return n - ((i << 1) >>> 31);}

还有一个和他类似的方法,我们可以看一下

    /*** 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.** <p>Note that this method is closely related to the logarithm base 2.* For all positive {@code int} values x:* <ul>* <li>floor(log<sub>2</sub>(x)) = {@code 31 - numberOfLeadingZeros(x)}* <li>ceil(log<sub>2</sub>(x)) = {@code 32 - numberOfLeadingZeros(x - 1)}* </ul>** @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.* @since 1.5*/public static int numberOfLeadingZeros(int i) {// HD, Figure 5-6if (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;}

这个是返回左边开始连续的为0的个数,这个可以参照上面一个,就不在详细分析,我们可以看到最后一行减去的是运算到最后i的第32位,和上面一个正好相反,因为这个方法返回的是左边开始0的个数。下面再看另一个方法

    /*** Returns the signum function of the specified {@code int} value.  (The* return value is -1 if the specified value is negative; 0 if the* specified value is zero; and 1 if the specified value is positive.)** @return the signum function of the specified {@code int} value.* @since 1.5*/public static int signum(int i) {// HD, Section 2-7return (i >> 31) | (-i >>> 31);}

这个很简单吧,看名字就知道什么意思,判断符号,正数返回1,负数返回-1,0返回0。如果i是正数,那么i >> 31肯定为0,-i为负数,-i >>> 31无符号右移,肯定为1,所以结果为1。当i为0的时候结果为0,这个就不在分析。当i为负数的时候,i >> 31结果为……1111(共32个1),-i >>> 31无论结果是什么,最终结果都是……1111(32个1),他是-1的补码,所以结果为-1。接着往下看

    /*** Returns the value obtained by rotating the two's complement binary* representation of the specified {@code int} value right by the* specified number of bits.  (Bits shifted out of the right hand, or* low-order, side reenter on the left, or high-order.)** <p>Note that right rotation with a negative distance is equivalent to* left rotation: {@code rotateRight(val, -distance) == rotateLeft(val,* distance)}.  Note also that rotation by any multiple of 32 is a* no-op, so all but the last five bits of the rotation distance can be* ignored, even if the distance is negative: {@code rotateRight(val,* distance) == rotateRight(val, distance & 0x1F)}.** @return the value obtained by rotating the two's complement binary*     representation of the specified {@code int} value right by the*     specified number of bits.* @since 1.5*/public static int rotateRight(int i, int distance) {return (i >>> distance) | (i << -distance);}

他表示循环右移指定位数,移除的不是舍去,而是补到左边,举个例子

        for (int i = 0; i < 100; i++) {System.out.println(buwei(Integer.toBinaryString(i)) + "===" + buwei(Integer.toBinaryString(Integer.rotateRight(i, 4))));}

看一下打印结果

只截取了前面的几个,他表示往右移动4位,移除的填充到左边。代码很好理解,如果distance为正数,i << -distance表示往左边移动(32-distance)位,i >>> distance表示往右边无符号移动distance位,还有另一个类似的方法

    public static int rotateLeft(int i, int distance) {return (i << distance) | (i >>> -distance);}

这个和上面一个相反,就不在详述,接着往下看

    /*** Returns an {@code int} value with at most a single one-bit, in the* position of the lowest-order ("rightmost") one-bit in the specified* {@code int} value.  Returns zero if the specified value has no* one-bits in its two's complement binary representation, that is, if it* is equal to zero.** @return an {@code int} value with a single one-bit, in the position*     of the lowest-order one-bit in the specified value, or zero if*     the specified value is itself equal to zero.* @since 1.5*/public static int lowestOneBit(int i) {// HD, Section 2-1return i & -i;}

这个返回的是从右边起遇到第一个1保留,其他的全部置为0,他和highestOneBit正好相反,highestOneBit表示从左边起遇到第一个1,其他位全部置0。代码很简洁。关于算法的基本上已经分析完了,下面来看一个重量级的类

    /*** Cache to support the object identity semantics of autoboxing for values between* -128 and 127 (inclusive) as required by JLS.** The cache is initialized on first usage.  The size of the cache* may be controlled by the -XX:AutoBoxCacheMax=<size> option.* During VM initialization, java.lang.Integer.IntegerCache.high property* may be set and saved in the private system properties in the* sun.misc.VM class.*/private static class IntegerCache {static final int low = -128;static final int high;static final Integer cache[];static {// high value may be configured by propertyint h = 127;String integerCacheHighPropValue =sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");if (integerCacheHighPropValue != null) {int i = parseInt(integerCacheHighPropValue);i = Math.max(i, 127);// Maximum array size is Integer.MAX_VALUEh = Math.min(i, Integer.MAX_VALUE - (-low) -1);}high = h;cache = new Integer[(high - low) + 1];int j = low;for(int k = 0; k < cache.length; k++)cache[k] = new Integer(j++);}private IntegerCache() {}}

他里面有个cache数组,缓存了-128到127共256Integer对象,每次创建Integer对象的时候,如果值为-128到127,就会从缓存中取,否则就会重新new一个,看一段代码

        Integer i1=120;Integer i2=120;Integer i3=130;Integer i4=130;System.out.println(i1==i2);System.out.println(i3==i4);

再来看一下运行结果

结果完全意料之中,因为i1和i2为120,小于127,从缓存中取,是同一对象,而i3和i4大于127,所以创建的是两个不同的对象。接着往下看

    /*** Returns an {@code Integer} instance representing the specified* {@code int} value.  If a new {@code Integer} instance is not* required, this method should generally be used in preference to* the constructor {@link #Integer(int)}, as this method is likely* to yield significantly better space and time performance by* caching frequently requested values.** This method will always cache values in the range -128 to 127,* inclusive, and may cache other values outside of this range.** @param  i an {@code int} value.* @return an {@code Integer} instance representing {@code i}.* @since  1.5*/public static Integer valueOf(int i) {assert IntegerCache.high >= 127;if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);}

从注释中也可以看到如果i的范围是-128到127,那么就从缓存中取,否则就new一个。接着decode(String nm)代码很简单就不在分析。另外有两个常用的方法toBinaryString和toHexString分别表示转化为二进制字符串和16进制字符串,其实调用的都是同一个方法toUnsignedString(int i, int shift),他表示将Integer转化为无符号字符串,来看一下

    private static String toUnsignedString(int i, int shift) {//int类型总共32位char[] buf = new char[32];int charPos = 32;//radix基数,如果是二进制radix为2,如果是16进制radix就为16,一般为2的n次方int radix = 1 << shift;//这个在讲到HashMap的时候说过,2的n次方减去1则后面全为1,原来为1的位置及之前全为0.int mask = radix - 1;do {//存到数组中buf[--charPos] = digits[i & mask];//偏移量,这里很好理解,因为Integer是32位,如果shift为3就是八进制,为4就是16进制,这里偏移就是按照多少进制来偏移的。i >>>= shift;} while (i != 0);return new String(buf, charPos, (32 - charPos));}

代码很简单,就不在详细介绍。记得以前经常会有这样的烦恼,就是如果我打印二进制的时候我要求必须打印32位,因为这样好进行比较,但实际情况不是这样,但可以把上面代码改一下达到要求

    private static String toUnsignedString(int i, int shift) {//int类型总共32位char[] buf = new char[32];Arrays.fill(buf, '0');//增加int charPos = 32;//radix基数,如果是二进制radix为2,如果是16进制radix就为16,一般为2的n次方int radix = 1 << shift;//这个在讲到HashMap的时候说过,2的n次方减去1则后面全为1,原来为1的位置及之前全为0.int mask = radix - 1;do {//存到数组中buf[--charPos] = digits[i & mask];//偏移量i >>>= shift;} while (i != 0);//return new String(buf, charPos, (32 - charPos));return new String(buf, 0, 32);//修改}

我们看一下

        for (int i = -100; i <100 ; i++) {System.out.println(toUnsignedString(i,1));}

再看一下运行结果,我从中间截取一部分

11111111111111111111111111110111
11111111111111111111111111111000
11111111111111111111111111111001
11111111111111111111111111111010
11111111111111111111111111111011
11111111111111111111111111111100
11111111111111111111111111111101
11111111111111111111111111111110
11111111111111111111111111111111
00000000000000000000000000000000
00000000000000000000000000000001
00000000000000000000000000000010
00000000000000000000000000000011
00000000000000000000000000000100
00000000000000000000000000000101
00000000000000000000000000000110

我们看到每个都是32位。

    final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,99999999, 999999999, Integer.MAX_VALUE };// Requires positive xstatic int stringSize(int x) {for (int i=0; ; i++)if (x <= sizeTable[i])return i+1;}

stringSize(int x)表示的x是几位数。0到9是一位数,10到99是两位数……。接下来看一下getChars(int i, int index, char[] buf)函数,他表示把i提取到buf中,index是buf的长度,通过DigitTens和DigitOnes可以看到i是转化为10进制的。这个函数比较复杂,打算在代码中分析

    /*** Places characters representing the integer i into the* character array buf. The characters are placed into* the buffer backwards starting with the least significant* digit at the specified index (exclusive), and working* backwards from there.** Will fail if i == Integer.MIN_VALUE*///从注释中可以看出,如果i==Integer.MIN_VALUE,这个方法将失效。static void getChars(int i, int index, char[] buf) {int q, r;int charPos = index;char sign = 0;//表示符号位if (i < 0) {sign = '-';i = -i;//如果i为负数,变为正数。}// Generate two digits per iterationwhile (i >= 65536) {//当大于65536的时候每两位开始操作q = i / 100;// really: r = i - (q * 100);//r是i对100求余的结果,相当于r=i%100;为什么不这样写,我个人认为应该是效率问题,通过移位操作效率要高一些,//((q << 6) + (q << 5) + (q << 2))相当于q*64+q*32+q*4也就是q*100;r = i - ((q << 6) + (q << 5) + (q << 2));i = q;//把数字存储到数组中,注意这个数组是从后往前存放的,如果仔细查看DigitTens和DigitOnes,可以发现DigitOnes[r]其实相当于DigitOnes[r%10],//DigitTens[r]其实相当于DigitTens[r/10]buf [--charPos] = DigitOnes[r];buf [--charPos] = DigitTens[r];}// Fall thru to fast mode for smaller numbers// assert(i <= 65536, i);for (;;) {//这里2^19=524288,(i * 52429) >>> (16+3)等于52429/524288=0.1000003814697266,相当于i除以10.因为乘法和移位的效率要高于除法,//至于上面的为什么没有使用乘法和移位,是因为当i大于65536的时候在乘法容易溢出,这里为什么要选择19,待会在下面再看q = (i * 52429) >>> (16+3);//求余,相当于r=i-q*10;上面的q约等于i/10;r = i - ((q << 3) + (q << 1));  // r = i-(q*10) ...buf [--charPos] = digits [r];//存放到数组中。i = q;if (i == 0) break;}if (sign != 0) {//如果i为负数,把负号添加到buf的前面,切记buf是从后往前添加的buf [--charPos] = sign;}}

下面来看一下上面为什么选择19的问题,我写了一段代码

 private static void calculate() {// 相乘的数不能比max大,否则当i接近65536的时候会出现Integer溢出,int max = (int) (Integer.MAX_VALUE * 1.0 / (1 << 16) * 10);// 1<<16相当于65536;int j = 0;// 移动j位接近maxint t = 1;// 临时变量,主要用于计算j的值。while (t < max) {t = (t << 1);j++;}// 最大移动位j,当1移动j位时相当于调用 highestOneBit(int i)函数。for (int m = 1; m <= j; m++) {int k = 1 << m;int mole = k % 10;int q = k / 10;if (mole >= 5)// 四舍五入q++;System.out.println(m + "→→→→" + q * 1.0d / k);}}

上面都有注释,很简单就不在介绍,下面看一下运行结果

1
0
1→→→→0.0
2→→→→0.0
3→→→→0.125
4→→→→0.125
5→→→→0.09375
6→→→→0.09375
7→→→→0.1015625
8→→→→0.1015625
9→→→→0.099609375
10→→→→0.099609375
11→→→→0.10009765625
12→→→→0.10009765625
13→→→→0.0999755859375
14→→→→0.0999755859375
15→→→→0.100006103515625
16→→→→0.100006103515625
17→→→→0.09999847412109375
18→→→→0.09999847412109375
19→→→→0.10000038146972656

我们看到当i越大的时候,结果越接近于0.1.所以选择i等于19.下面再看另一个方法toString(int i),代码也很简单,就简单介绍一下

    /*** Returns a {@code String} object representing the* specified integer. The argument is converted to signed decimal* representation and returned as a string, exactly as if the* argument and radix 10 were given as arguments to the {@link* #toString(int, int)} method.** @param   i   an integer to be converted.* @return  a string representation of the argument in base 10.*/public static String toString(int i) {if (i == Integer.MIN_VALUE)return "-2147483648";// Android-changed: cache the string literal for small values.boolean negative = i < 0;//判断是否是负数boolean small = negative ? i > -100 : i < 100;if (small) {//如果i大于等于-100并且小于等于100,则从缓存中取final String[] smallValues = negative ? SMALL_NEG_VALUES : SMALL_NONNEG_VALUES;if (negative) {i = -i;if (smallValues[i] == null) {//如果缓存为空则创建smallValues[i] =i < 10 ? new String(new char[]{'-', DigitOnes[i]}): new String(new char[]{'-', DigitTens[i], DigitOnes[i]});}} else {if (smallValues[i] == null) {//如果缓存为空则创建smallValues[i] =i < 10 ? new String(new char[]{DigitOnes[i]}): new String(new char[]{DigitTens[i], DigitOnes[i]});}}return smallValues[i];}//如果不是在缓存的范围之内,则调用getChars方法,看到下面如果为负数时,size会加1,因为在getChars的最后两行要判断符号位的int size = negative ? stringSize(-i) + 1 : stringSize(i);char[] buf = new char[size];getChars(i, size, buf);// Android-changed: change string constructor.return new String(buf);}

还有一个类似的toString(int i, int radix)方法,不过上面返回的是十进制的,这个可以根据传的进制参数返回,比上一个要智能,看一下

    public static String toString(int i, int radix) {//如果radix小于2或者大于36,则返回10进制。Character.MIN_RADIX为2,Character.MAX_RADIX是36// public static final int MAX_RADIX = 36;if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)radix = 10;/* Use the faster version */if (radix == 10) {//如果十进制调用上一个方法return toString(i);}char buf[] = new char[33];boolean negative = (i < 0);int charPos = 32;if (!negative) {// 如果不为负数,让i变为负数。i = -i;}while (i <= -radix) {int q = i / radix;//这里radix * q - i相当于对i求余,如果理解不了可以把radix想象为10进制估计就好一些了buf[charPos--] = digits[radix * q - i];i = q;}buf[charPos] = digits[-i];if (negative) {// 如果为负数添加负号buf[--charPos] = '-';}return new String(buf, charPos, (33 - charPos));}

下面再看最后一个方法parseInt

    public static int parseInt(String s, int radix)throws NumberFormatException{/** WARNING: This method may be invoked early during VM initialization* before IntegerCache is initialized. Care must be taken to not use* the valueOf method.*/if (s == null) {throw new NumberFormatException("null");}if (radix < Character.MIN_RADIX) {throw new NumberFormatException("radix " + radix +" less than Character.MIN_RADIX");}if (radix > Character.MAX_RADIX) {throw new NumberFormatException("radix " + radix +" greater than Character.MAX_RADIX");}int result = 0;// 根据最后一行的判断,result保存的是负数.boolean negative = false;//判断是否是负数int i = 0, len = s.length();int limit = -Integer.MAX_VALUE;//正数的极限值int multmin;int digit;if (len > 0) {char firstChar = s.charAt(0);//这里主要判断如果是负数的操作。if (firstChar < '0') { // Possible leading "+" or "-"if (firstChar == '-') {// 是负数negative = true;limit = Integer.MIN_VALUE;//如果是负数,则极限值是Integer.MIN_VALUE} else if (firstChar != '+')//如果小于0,并且既不是"-"又不是"+"直接抛异常throw NumberFormatException.forInputString(s);if (len == 1) // Cannot have lone "+" or "-"//如果只是一个符号也抛异常throw NumberFormatException.forInputString(s);i++;}multmin = limit / radix;while (i < len) {// Accumulating negatively avoids surprises near MAX_VALUEdigit = Character.digit(s.charAt(i++),radix);if (digit < 0) {//数字不能小于0throw NumberFormatException.forInputString(s);}if (result < multmin) {//如果不判断,下面相乘会出现溢出,超过极限值,为什么要用小于,是因为result和multmin都是负数,throw NumberFormatException.forInputString(s);}//逐个取出每一个字符与radix相乘,radix表示进制,比如2,8,10,10等,如果还是不好理解,就把radix想象为10进制吧。result *= radix;if (result < limit + digit) {//这里为什么要这样判断,是因为limit是负数,digit是正数,防止下面的操作导致结果溢出throw NumberFormatException.forInputString(s);}result -= digit;//注意这里为什么要减,因为result是负数,在最后才进行符号判断}} else {throw NumberFormatException.forInputString(s);}return negative ? result : -result;//如果知道result是负数,这里就好理解了}

OK,到现在为止Integer的所有方法基本都已分析完毕

Integer源码详解相关推荐

  1. java的数组与Arrays类源码详解

    java的数组与Arrays类源码详解 java.util.Arrays 类是 JDK 提供的一个工具类,用来处理数组的各种方法,而且每个方法基本上都是静态方法,能直接通过类名Arrays调用. 类的 ...

  2. Spring事务源码详解

    一. 简介 事务: 事务是逻辑上的一组操作,要么都执行,要么都不执行,关于事务的基本知识可以看我的这篇文章:事务的基础知识 Spring事务: Spring 支持两种方式的事务管理:编程式事务管理.声 ...

  3. java的String类源码详解

    java的String类源码详解 类的定义 public final class Stringimplements java.io.Serializable, Comparable<String ...

  4. java源码详解——String类

    java源码详解--String类目录: Java String 类 下面开始介绍主要方法: Java charAt() 方法 Java compareTo() 方法 int compareTo(St ...

  5. 【Live555】live555源码详解(九):ServerMediaSession、ServerMediaSubsession、live555MediaServer

    [Live555]live555源码详解系列笔记 继承协作关系图 下面红色表示本博客将要介绍的三个类所在的位置: ServerMediaSession.ServerMediaSubsession.Dy ...

  6. 【Live555】live555源码详解系列笔记

    [Live555]liveMedia下载.配置.编译.安装.基本概念 [Live555]live555源码详解(一):BasicUsageEnvironment.UsageEnvironment [L ...

  7. 【Live555】live555源码详解(八):testRTSPClient

    [Live555]live555源码详解系列笔记 继承协作关系图 下面红色表示本博客将要介绍的testRTSPClient实现的三个类所在的位置: ourRTSPClient.StreamClient ...

  8. 【Live555】live555源码详解(七):GenericMediaServer、RTSPServer、RTSPClient

    [Live555]live555源码详解系列笔记 继承协作关系图 下面红色表示本博客将要介绍的三个类所在的位置: GenericMediaServer.RTSPServer.RTSPClient 14 ...

  9. 【Live555】live555源码详解(六):FramedSource、RTPSource、RTPSink

    [Live555]live555源码详解系列笔记 继承协作关系图 下面红色表示本博客将要介绍的三个类所在的位置: FramedSource.RTPSource.RTPSink 11.FramedSou ...

最新文章

  1. Effective C# 原则11:选择foreach循环
  2. python虚拟环境-conda
  3. 杭州线下|2019产品经理年终轰趴
  4. CET6级高频词(按频度)(700个)
  5. assignment symbolic automaton verilog设计
  6. qt 实现 以图片为中心 让它旋转_QT图片旋转动画
  7. Powershell进阶学习(1) 浅谈Powershell学习方法
  8. JavaScript小练习2
  9. 快速更换证件照底色的方法
  10. 南澳大学计算机科学专业学费,澳洲南澳大学生活费
  11. 遥感影像数据产品级别
  12. DualClip Translator 2.4 汉化版(在线翻译器)推介
  13. 电影-《满城尽带黄金甲》
  14. 今天项目报错: No operations allowed after connection closed
  15. 成都java到底怎么样?发展前景如何?
  16. 如何通过BI构建一份企业经营报表
  17. 书单|刀剑如梦,如何走好自己的江湖路?
  18. 业务还是技术测试?从初级软件测试到高级测试工程师,我都经历了什么......
  19. Shopify批量上货助手-Shopify独立站
  20. 眼动数据分析基础_数据和指标的导出

热门文章

  1. SOD算法:PoolNet
  2. summernote富文本实现图片的删除
  3. 卖股票缴税,卖房避税,马斯克的“阳谋”要结束了
  4. 俄罗斯央行:犯罪分子很少使用加密货币来回笼资金
  5. 台式电脑:点击开启虚拟机报错:此主机支持intel vy-x, 但intel vy-x处于禁用状态
  6. AR试妆魔镜操作演示
  7. WCF自定义扩展,以实现aop!
  8. 计算机音乐博士,美国音乐博士解析
  9. Here Document免交互和Expect自动化交互
  10. 强化学习笔记:连续控制 确定策略梯度DPG