JDK源码之Integer类—reverse()方法

reverse()方法的功能是将一个int类型数值的所有二进制位反转,然后返回反转后的int数值

例如数字987654321的二进制是0011 1010 1101 1110 0110 1000 1011 0001,反转二进制位后是1000 1101 0001 0110 0111 1011 0101 1100。

简单的来说所谓的反转就是:如字符串"ABCD",反转后的字符串是"DCBA",而该方法就是反转二进制位。

该方法的源代码如下:

    /**
     * 返回通过反转指定int值的二进制补码二进制表示中的位顺序而获得的值。
     * 例如数字987654321的二进制是0011 1010 1101 1110 0110 1000 1011 0001
     * 反转二进制位后是1000 1101 0001 0110 0111 1011 0101 1100
     *
     * @param i 要进行反转的int值
     * @return 返回反转二进制位后的数值
     */
    public static int reverse(int i) {
        i = (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;
    }

该算法的思路是:将32位二进制每两位分组,然后交换每组中相邻的单1位;再每四位分组,交换每组中相邻的2位;再每八位分组,交换每组中相邻的4位;再每十六位、三十二位进行同样的操作。

用字符串来演示该思路,如下:

字符串:"ABCDEFGHIJKLMNOP",反转后的字符串是:"PONMLKJIHGFEDCBA"
两两分组交换相邻1位的字符
AB CD EF GH IJ KL MN OP
BA DC FE HG JI LK NM PO
四四分组交换相邻2位的字符
BADC FEHG JILK NMPO
DCBA HGFE LKJI PONM
八八分组交换相邻4位的字符
DCBAHGFE LKJIPONM
HGFEDCBA PONMLKJI
十六十六分组交换相邻8位的字符
HGFEDCBAPONMLKJI
PONMLKJIHGFEDCBA
完成反转

用二进制来演示该思路:

例如对十进制数字12345678进行反转
    第一步,两两分组12 34 56 78,交换每组中相邻的单1位21 43 65 87
    第二步,四四分组2143 6587,交换每组中相邻的2位4321 8765
    第三步,八八分组43218765,交换每组中相邻的4位87654321,完成反转
例如数字987654321的二进制0011 1010 1101 1110 0110 1000 1011 0001
    第一步,两两分组        00 11 10 10 11 01 11 10 01 10 10 00 10 11 00 01
        交换每组中相邻的1位 00 11 01 01 11 10 11 01 10 01 01 00 01 11 00 10
    第二步,四四分组        0011 0101 1110 1101 1001 0100 0111 0010
        交换每组中相邻的2位 1100 0101 1011 0111 0110 0001 1101 1000
    第三步,八八分组        11000101 10110111 01100001 11011000
        交换每组中相邻的4位 01011100 01111011 00010110 10001101
    第四步,十六十六分组     0101110001111011 0001011010001101
        交换每组中相邻的8位  0111101101011100 1000110100010110
    第五步,三十二三十二分组  01111011010111001000110100010110
        交换每组中相邻的16位 10001101000101100111101101011100

交换的过程如下:

该方法代码的执行过程如下:

/*
        i = (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);

        0x55555555=0101 0101 0101 0101 0101 0101 0101 0101
        0xAAAAAAAA=1010 1010 1010 1010 1010 1010 1010 1010
        0x33333333=0011 0011 0011 0011 0011 0011 0011 0011
        0xCCCCCCCC=1100 1100 1100 1100 1100 1100 1100 1100
        0x0f0f0f0f=0000 1111 0000 1111 0000 1111 0000 1111
        0xf0f0f0f0=1111 0000 1111 0000 1111 0000 1111 0000
        0xff00    =0000 0000 0000 0000 1111 1111 0000 0000

        以数字987654321的二进制是0011 1010 1101 1110 0110 1000 1011 0001为例
        ①x = (i & 0x55555555) <<  1 | (i & 0xAAAAAAAA) >>>  1;等价于i = (i & 0x55555555) << 1 | (i >>> 1) & 0x55555555
            (i & 0x55555555)
                00 11 10 10 11 01 11 10 01 10 10 00 10 11 00 01
               &
                01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
               =00 01 00 00 01 01 01 00 01 00 00 00 00 01 00 01     两两分组,然后保留每组中的低1位
            (i & 0x55555555) << 1
                00 10 00 00 10 10 10 00 10 00 00 00 00 10 00 10     左移1位,为两两分组中每组的相邻1位的交换做准备
            (i & 0xAAAAAAAA)
                00 11 10 10 11 01 11 10 01 10 10 00 10 11 00 01
               &
                10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
               =00 10 10 10 10 00 10 10 00 10 10 00 10 10 00 00     两两分组,然后保留每组中的高1位
            (i & 0xAAAAAAAA) >>>  1
                00 01 01 01 01 00 01 01 00 01 01 00 01 01 00 00     无符号右移1位,为两两分组中每组的相邻1位的交换做准备
            (i & 0x55555555) <<  1 | (i & 0xAAAAAAAA) >>>  1
                00 10 00 00 10 10 10 00 10 00 00 00 00 10 00 10
               |
                00 01 01 01 01 00 01 01 00 01 01 00 01 01 00 00
               =00 11 01 01 11 10 11 01 10 01 01 00 01 11 00 10     交换两两分组中每组中相邻的1位
       ②i = (i & 0x33333333) << 2 | (i & 0xCCCCCCCC)>>>2;等价于i = (i & 0x33333333) << 2 | (i >>> 2) & 0x33333333;
            (i & 0x33333333)
                0011 0101 1110 1101 1001 0100 0111 0010
               &
                0011 0011 0011 0011 0011 0011 0011 0011
               =0011 0001 0010 0001 0001 0000 0011 0010             四四分组,然后保留每组中的低2位
           (i & 0x33333333) << 2
                1100 0100 1000 0100 0100 0000 1100 1000             左移2位,为四四分组中每组的相邻2位的交换做准备
           (i & 0xCCCCCCCC)
                0011 0101 1110 1101 1001 0100 0111 0010
               &
                1100 1100 1100 1100 1100 1100 1100 1100
               =0000 0100 1100 1100 1000 0100 0100 0000             四四分组,然后保留每组中的高2位
           (i & 0xCCCCCCCC)>>>2
                0000 0001 0011 0011 0010 0001 0001 0000             无符号右移2位,为四四分组中每组的相邻2位的交换做准备
           (i & 0x33333333) << 2 | (i & 0xCCCCCCCC)>>>2
                1100 0100 1000 0100 0100 0000 1100 1000
               |
                0000 0001 0011 0011 0010 0001 0001 0000
               =1100 0101 1011 0111 0110 0001 1101 1000             交换四四分组中每组中相邻的2位
        ③i = (i & 0x0f0f0f0f) << 4 | (i & 0xf0f0f0f0) >>> 4;等价于i = (i & 0x0f0f0f0f) << 4 | (i >>> 4) & 0x0f0f0f0f;
            (i & 0x0f0f0f0f)
               11000101 10110111 01100001 11011000
              &
               00001111 00001111 00001111 00001111
              =00000101 00000111 00000001 00001000                  八八分组,然后保留每组中的低4位
            (i & 0x0f0f0f0f) << 4
               01010000 01110000 00010000 10000000                  左移4位,为八八分组中每组的相邻4位的交换做准备
            (i & 0xf0f0f0f0)
               11000101 10110111 01100001 11011000
              &
               11110000 11110000 11110000 11110000
              =11000000 10110000 01100000 11010000                  八八分组,然后保留每组中的高4位
           (i & 0xf0f0f0f0) >>> 4
               00001100 00001011 00000110 00001101                  无符号右移4位,为八八分组中每组的相邻4位的交换做准备
          (i & 0x0f0f0f0f) << 4 | (i & 0xf0f0f0f0) >>> 4
               01010000 01110000 00010000 10000000
              |
               00001100 00001011 00000110 00001101
              =01011100 01111011 00010110 10001101                  交换八八分组中每组中相邻的4位
       ④(i << 24) | ((i & 0xff00) << 8) | ((i >>> 8) & 0xff00) | (i >>> 24)
              (i << 24)
                  10001101 00000000 00000000 00000000               保留三十二位中的从左往右数第四个八位二进制10001101,保留在从左往右数第一个八位的位置
              ((i & 0xff00) << 8)
              (i & 0xff00)
                  01011100 01111011 00010110 10001101
                 &
                  00000000 00000000 11111111 00000000
                 =00000000 00000000 00010110 00000000
              (i & 0xff00) << 8
                  00000000 00010110 00000000 00000000               保留三十二位中的从左往右数第三个八位二进制00010110,保留在从左往右数第二个八位的位置
              ((i >>> 8) & 0xff00)
              (i >>> 8)
                 00000000 01011100 01111011 00010110
              ((i >>> 8) & 0xff00)
                 00000000 01011100 01111011 00010110
                &
                 00000000 00000000 11111111 00000000
                =00000000 00000000 01111011 00000000                保留三十二位中的从左往右数第二个八位二进制01111011,保留在从左往右数第三个八位的位置
              (i >>> 24)
                 00000000 00000000 00000000 01011100                保留三十二位中的从左往右数第一个八位二进制01011100,保留在从左往右数第四个八位的位置
              (i << 24) | ((i & 0xff00) << 8) | ((i >>> 8) & 0xff00) | (i >>> 24)
                 10001101 00000000 00000000 00000000
                |
                 00000000 00010110 00000000 00000000
                |
                 00000000 00000000 01111011 00000000
                |
                 00000000 00000000 00000000 01011100
                =10001101 00010110 01111011 01011100                将已经交换位置的八位二进制整合到一起
 */

x = (i & 0x55555555) <<  1 | (i & 0xAAAAAAAA) >>>  1;等价于i = (i & 0x55555555) << 1 | (i >>> 1) & 0x55555555这样的代码中,其中i = (i & 0x55555555) << 1 | (i >>> 1) & 0x55555555是对前者代码的优化,源码中的就是优化代码,但是我们看未优化的代码才能更加方便地理解这个算法的原理。

第①、②、③步都是一样的原理,第④其实也是,但它的代码和reverseByte()方法的源码一致,可以看看该方法来加深理解。

第③步移位过程图解(i = (i & 0x0f0f0f0f) << 4 | (i & 0xf0f0f0f0) >>> 4;

关于优化代码和未优化代码的模拟比较:

  • 未优化代码【i = (i & 0x0f0f0f0f) << 4 | (i & 0xf0f0f0f0) >>> 4;】:先保留每组的低4位,剔除掉每组高4位的数据(即将高4位全部置为0),然后将低4位移到高4位位置;再保留每组的高4位,剔除掉每组低4位的数据(即将低4位全部置为0),然后将高4位移到低4位位置;最后用或运算整合每组的低4位和高4位。
  • 优化代码【i = (i & 0x0f0f0f0f) << 4 | (i >>> 4) & 0x0f0f0f0f;】:先保留每组的低4位,剔除掉每组高4位的数据(即将高4位全部置为0),然后将低4位移到高4位位置;再将每组的高4位移动到低4位的位置(即用每组的高4位替换掉低4位),再剔除掉高4位的数据(即将高4位全部置为0);最后用或运算整合每组的低4位和高4位。
        ③i = (i & 0x0f0f0f0f) << 4 | (i & 0xf0f0f0f0) >>> 4;等价于i = (i & 0x0f0f0f0f) << 4 | (i >>> 4) & 0x0f0f0f0f;
            (i & 0x0f0f0f0f)
               11000101 10110111 01100001 11011000
              &
               00001111 00001111 00001111 00001111
              =00000101 00000111 00000001 00001000                  八八分组,然后保留每组中的低4位
            (i & 0x0f0f0f0f) << 4
               01010000 01110000 00010000 10000000                  左移4位,为八八分组中每组的相邻4位的交换做准备
            (i & 0xf0f0f0f0)
               11000101 10110111 01100001 11011000
              &
               11110000 11110000 11110000 11110000
              =11000000 10110000 01100000 11010000                  八八分组,然后保留每组中的高4位
           (i & 0xf0f0f0f0) >>> 4
               00001100 00001011 00000110 00001101                  无符号右移4位,为八八分组中每组的相邻4位的交换做准备
          (i & 0x0f0f0f0f) << 4 | (i & 0xf0f0f0f0) >>> 4
               01010000 01110000 00010000 10000000
              |
               00001100 00001011 00000110 00001101
              =01011100 01111011 00010110 10001101                  交换八八分组中每组中相邻的4位
        ③i = (i & 0x0f0f0f0f) << 4 | (i >>> 4) & 0x0f0f0f0f;
            (i & 0x0f0f0f0f)
               11000101 10110111 01100001 11011000
              &
               00001111 00001111 00001111 00001111
              =00000101 00000111 00000001 00001000                  八八分组,然后保留每组中的低4位
            (i & 0x0f0f0f0f) << 4
               01010000 01110000 00010000 10000000                  左移4位,为八八分组中每组的相邻4位的交换做准备
            (i >>> 4)
               00001100 01011011 01110110 00011101                  将每组的高4位移动到每组的低4位中,覆盖掉原来的低4位,也相当于保留了高4位
            (i >>> 4) & 0x0f0f0f0f
               00001100 01011011 01110110 00011101
              &
               00001111 00001111 00001111 00001111
              =00001100 00001011 00000110 00001101                  剔除掉高4位中不必要数据,我们只需要每组的低4位参与运算
            (i & 0x0f0f0f0f) << 4 | (i >>> 4) & 0x0f0f0f0f
               01010000 01110000 00010000 10000000
              |
               00001100 00001011 00000110 00001101
              =01011100 01111011 00010110 10001101

参考链接:Integer相关方法的源码解析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值