java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言, 是由 Sun Microsystems 公司于 1995 年 5 月推出的 Java 程序设计语言和 Java 平台 (即 JavaEE(j2ee), JavaME(j2me), JavaSE(j2se)) 的总称
这篇文章主要介绍了 Java 源码解析 Integer 方法解读, 包括 toString 方法 toUnsignedString 方法 highestOneBit 方法等, 具有一定的参考价值, 感兴趣的小伙伴们可以参考一下
toUnsignedString 方法解读
看到 Integer 中有这样的一个方法把 int 转为 Unsigned 类型的字符串, 但是有几个点不是很清楚, 经过查询资料弄懂了, 解读如下:
- /**
- * Convert the integer to an unsigned number.
- */
- private static String toUnsignedString(int i, int shift) {
- char[] buf = new char[32];
- int charPos = 32;
- int radix = 1 << shift;
- int mask = radix - 1;
- do {
- buf[--charPos] = digits[i & mask];
- i >>>= shift;
- } while ( i != 0 );
- return new String(buf, charPos, (32 - charPos));
- }
这里的参数 shift 是代表的进制, 如果是二进制的话 shift 是 2, 八进制那么就是 8, 相应的其 mask 就计算成 1 和 7 了通过 mask 与 i 相与不断取出 digits 数组中对应的字符
在就是 i 每次进行逻辑右移的运算, 最高位补充零, 这样最终经过不断的逻辑右移后 i 会变为 0
此外, 采用 do-while 是防止 i 本身是 0 的情况下, buf 数组无法获得其值
toString 方法解读
- // 这个数组表示的是数字的十位部分, 下面会用到这个数组
- final static char [] DigitTens = {
- '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
- '1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
- '2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
- '3', '3', '3', '3', '3', '3', '3', '3', '3', '3',
- '4', '4', '4', '4', '4', '4', '4', '4', '4', '4',
- '5', '5', '5', '5', '5', '5', '5', '5', '5', '5',
- '6', '6', '6', '6', '6', '6', '6', '6', '6', '6',
- '7', '7', '7', '7', '7', '7', '7', '7', '7', '7',
- '8', '8', '8', '8', '8', '8', '8', '8', '8', '8',
- '9', '9', '9', '9', '9', '9', '9', '9', '9', '9',
- } ;
- // 这个数组表示的是数字的个位部分, 下面会用到这个数组把数组的每个部分进行组合的话可以得到 100 以内的所有的情况的二位整数
- final static char [] DigitOnes = {
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
- } ;
- public static String toString(int i) {
- if (i == Integer.MIN_VALUE)
- // 这里的加 1, 开始不太清楚什么意思, 后来发现负数的话
- // 需要在前面加负号的所以串的大小要加 1 才行
- // 这里传入 stringSize 的部分是正的, 在下面的数组中
- // 进行映射
- int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
- char[] buf = new char[size];
- getChars(i, size, buf);
- return new String(0, size, buf);
- }
- static void getChars(int i, int index, char[] buf) {
- int q, r;
- int charPos = index;
- char sign = 0;
- if (i < 0) {
- sign = '-';
- i = -i;
- }
- // 超过 65536 的整数, 先进行下面这样的一个处理,
- // 这个处理中以 100 为单位, 也就是, 余数控制在两位
- // 这样正好映射到上面的十位和个位数组, 一次性写入
- // buf 数组中两位, 这样毫无疑问比求出每一位是要快很多的
- while (i >= 65536) {
- q = i / 100;
- // really: r = i - (q * 100);
- r = i - ((q << 6) + (q << 5) + (q << 2));
- i = q;
- buf [--charPos] = DigitOnes[r];
- buf [--charPos] = DigitTens[r];
- }
- // Fall thru to fast mode for smaller numbers
- // assert(i <= 65536, i);
- // 对于小于等于 65536 的整数而言, 可以直接进行下面的部分
- // 而且这个地方是以除以 10 进行的, 但是实现并不是直接除
- // 而是先求一个 52429/2^19 约等于 0.1000...
- // 相当于 i 除以了 10, 但是我不清楚的是为什么这里不直接
- // 除以 10, 或许是因为精度不够吧, 除法产生浮点数,
- // 或许会不精确, 然后得到的除数再乘以 10, 得到 10 位以上
- // 部分的数, 通过 i - 该部分十位以上的数, 得到个位的数字
- for (;;) {
- q = (i * 52429) >>> (16+3);
- r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ...
- buf [--charPos] = digits [r];
- i = q;
- if (i == 0) break;
- }
- if (sign != 0) {
- buf [--charPos] = sign;
- }
- }
- final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
- 99999999, 999999999, Integer.MAX_VALUE };
- // 这里应该是进行了优化, 通过 sizeTable 存储了整型数据的位
- // 的情况, 从一位一直到 10 位: 2147483647 的情况,
- // 这个处理方式很巧妙
- static int stringSize(int x) {
- for (int i=0; ; i++)
- if (x <= sizeTable[i])
- return i+1;
- }
highestOneBit 方法解读
- public static int highestOneBit(int i) {
- // HD, Figure 3-1
- i |= (i >> 1);
- i |= (i >> 2);
- i |= (i >> 4);
- i |= (i >> 8);
- i |= (i >> 16);
- return i - (i >>> 1);
- }
这个方法很有意思, 我自己算了算, 然后才明白了他的精髓, 这个方法的作用是求构成一个整数的最大的位所代表的整数的值这里通过位移的方式实现了这个功能接下来举个简单的例子, 128 来讲二进制是 1000 0000 下面以他为例子算下:
移 1 位
- 1000 0000
- 0100 0000
- |-------------
移 2 位
- 1100 0000
- 0011 0000
- |------------
移 4 位
- 1111 0000
- 0000 1111
- |------------
移 8 位
- 1111 1111
- 0000 0000
- |------------
移动 16 位
- 1111 1111
- 0000 0000
- |------------
- 1111 1111
最终的结果如你所看到的, 后面的位全部填充为 1, 把后面的位全部减掉就得到了最高的位代表的整数
bitCount 方法解析
- public static int bitCount(int i) {
- // HD, Figure 5-2
- i = 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;
- }
这个方法着实废了半天功夫研究, 后来算是搞懂了个大概:
第一行, 实现的是把整型的二进制位进行两个两个的分组, 然后统计这两个位中的 1 的个数, 我不知道这个公式是怎么来的, 但是算出来确实是这样的
第二行, 实现的是把整型的二进制位进行四个四个的分组, 然后计算段内移位相加, 就是 1001-> 10 + 01 = 11 相当于三个 1 了
第三行, 就是把整型的二进制位八个一组, 然后类似上面的方式, 进行位移相加, 当然这里通过一些特定的移位以及与运算实现的
接下来就是十六个一组, 三十二个一组最终将统计数字归并到最后的几位表示的统计数值中
来源: http://www.phperz.com/article/18/0213/359184.html