java 位运算

  • 2020 年 10 月 23 日
  • 筆記

| (位或运算)

在运算位或中,两个数值的二进制码中只要对应位中一个位1那么当前对应位运算结果位1

  java中一个int字节占4位,一位8个字节码

        15 二进制码 ---》ob 0000 0000 0000 0000 0000 0000 0000 1111

        25 二进制码 ---》ob 0000 0000 0000 0000 0000 0000 0001 1001

        (进行位或运算)
        ob 0000 0000 0000 0000 0000 0000 0000 1111
        | (位或运算符)
        ob 0000 0000 0000 0000 0000 0000 0001 1001

       =ob  0000 0000 0000 0000 0000 0000 0001 1111(对应位其中一个为1则结果为1)

& (位与运算)

在运算位与中,两个数值的二进制码中对应位两个数值都为1则结果为1否则结果为0

        30 二进制码---》 ob 0000 0000 0000 0000 0000 0000 0001 1110

        35 二进制码---》 ob 0000 0000 0000 0000 0000 0000 0010 0011
        
        (进行位与运算)
        ob 0000 0000 0000 0000 0000 0000 0001 1110
        &(位于运算符)
        ob 0000 0000 0000 0000 0000 0000 0010 0011

       =ob 0000 0000 0000 0000 0000 0000 0000 0010(对应为两个都为1则结果为1)

^(位异或运算)

在位异或运算中,两个数值的二进制码中对位的两个数值相等则结果为0,不等结果为1

        40 二进制码---》 ob 0000 0000 0000 0000 0000 0000 0010 1000

        45 二进制码---》 ob 0000 0000 0000 0000 0000 0000 0010 1101

        (进行异或运算)
        ob 0000 0000 0000 0000 0000 0000 0010 1000
        ^
        ob 0000 0000 0000 0000 0000 0000 0010 1101

       =ob 0000 0000 0000 0000 0000 0000 0000 0101(对应位相等结果为0,不等结果为1)

计算机中负数的表示

在java中所有操作的数值都是数据的补码,正数的二进制源码、反码,补码都是一样的

负数的补码 (最高位为符号位)

  -6 源码 ob 1000 0000 0000 0000 0000 0000 0000 0110
     反码 ob 1111 1111 1111 1111 1111 1111 1111 1001
     补码(在其反码上+1)
          ob 1111 1111 1111 1111 1111 1111 1111 1010

所以在java中-6的存储的格式为 ob 1111 1111 1111 1111 1111 1111 1111 1010

<<(位左移运算)

在位左计算中,就是将数值的二进制补码向左移两位(左移操作会使数值增大————2的移动位数的次方增长)
正数左移
10<<2
ob 0000 0000 0000 0000 0000 0000 0000 1010
2<<(左移两位)
ob 0000 0000 0000 0000 0000 0000 0010 1000
= 40

  负数左移
  -10<<2
  ob 1000 0000 0000 0000 0000 0000 0000 1010(源码)
  ob 1111 1111 1111 1111 1111 1111 1111 0101(符号位不管 反码)
  ob 1111 1111 1111 1111 1111 1111 1111 0110(补码)
  2<<(左移两位)
  ob 1111 1111 1111 1111 1111 1111 1101 1000(得到左移后的补码)
  -                                        1
  ob 1111 1111 1111 1111 1111 1111 1101 0111(补码减一得到反码)

  ob 1000 0000 0000 0000 0000 0000 0010 1000(得到源码)
  =-40

>>(位右移运算)

在位右移运算中,就是将数值的补码向右移动相应的位数,左边空出来的位数用符号位填充(右移操作会使操作数缩小————2的右移位数的次方数缩小)

  正数右移
  20>>2
  ob 0000 0000 0000 0000 0000 0000 0001 0100
  >>2(右移两位)
  ob 0000 0000 0000 0000 0000 0000 0000 0101
  =5
  负数右移
  -30>>1
  ob 1000 0000 0000 0000 0000 0000 0001 1110(源码)
  ob 1111 1111 1111 1111 1111 1111 1110 0001 (符号位不管 反码)
  ob 1111 1111 1111 1111 1111 1111 1110 0010(补码)
  
  >>1
  ob 1111 1111 1111 1111 1111 1111 111 0001(计算后的补码)
  -                                        1
  ob 1111 1111 1111 1111 1111 1111 1111 0000(计算后的补码-1得到计算后的反码)
  ob 1000 0000 0000 0000 0000 0000 0000 1111
  =-15

>>>(无符号右移)

无符号右移,就是将数值的补码向右移动相应的位数,左边空出的用0补,正数和右移一样,而负数是不管符号位,也就是所一个负数经过无符号右移会转换位一个正数

  -15>>>2
  ob 1000 0000 0000 0000 0000 0000 0000 1111
  ob 1111 1111 1111 1111 1111 1111 1111 0000
  ob 1111 1111 1111 1111 1111 1111 1111 0001

  >>>2(无符号右移)
  ob 0011 1111 1111 1111 1111 1111 1111 1100(正数的补码,反码,源码一样)
  =1073741820

实例讲解hashmap中根据传入的散列表长度计算散列扩容阈值

 static final int tableSizeFor(int cap) {
    int n = cap - 1;
    n |= n >>> 1;
    n |= n >>> 2;
    n |= n >>> 4;
    n |= n >>> 8;
    n |= n >>> 16;
    return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}

  如果传如15即cap=15
  1、n=15-1 =14;
  14二进制码 --》ob 0000 0000 0000 0000 0000 0000 0000 1110
  2、n|= n>>>1

  ob 0000 0000 0000 0000 0000 0000 0000 1110
  >>> 1 (无符号右移1位)
  ob 0000 0000 0000 0000 0000 0000 0000 0111
  |
  ob 0000 0000 0000 0000 0000 0000 0000  1110
 =ob 0000 0000 0000 0000 0000 0000 0000 1111

  n=15
  3、n |= n >>> 2;
  ob  0000 0000 0000 0000 0000 0000 0000 1111
   >>>2
  ob  0000 0000 0000 0000 0000 0000 0000 0011
  |
  ob  0000 0000 0000 0000 0000 0000 0000 1111
 =ob  0000 0000 0000 0000 0000 0000 0000 1111
  
  n=15
  4、  n |= n >>> 4;
  
  ob  0000 0000 0000 0000 0000 0000 0000 1111
  >>>4
  ob  0000 0000 0000 0000 0000 0000 0000 0000
  |
  ob  0000 0000 0000 0000 0000 0000 0000 1111
 =ob  0000 0000 0000 0000 0000 0000 0000 1111

  n=15
  后面就不用算了呀,ob  0000 0000 0000 0000 0000 0000 0000 1111这个不管向右移大于4位后。就已经全部为0了
  在与ob  0000 0000 0000 0000 0000 0000 0000 1111 或运算一下还是这个是ob  0000 0000 0000 0000 0000 0000 0000 1111
  最后得出当传入初始化数值为15时,扩容阈值为16.当然这个值是在初始hashmap是传入了散列表参数时。
  如果是默认长度,那么是散列表的默认长度*0.75