深刻理解Java位移运算符

 移位操作符操作的运算对象是二进制的位(Bit),只可用来处理整数类型(基本类型的一种)。移位操作可分为 左移操作符(<<)、“有符号”右移操作符(>>)、“无符号”右移操操作符(>>>)三种。

左移操作符 ( <<): 

value << num     value指定移动的值  num指定移动的位数

运算规则:

  • 按照操作符右侧指定的位数将左边的操作数向左边移动(高位移除,在低位补0);
  • 当左移的操作数是int类型时,每移动一位它的第31位就要被移除(位数以第0位开始);
  • 当左移的操作数是long类型时,每移动一位 它的第63位就要被移除;
  • 当左边的操作数为byte、short类型时,它们会被转换为int类型,其结果要是int类型。
  • 在左移过程中正数可能移为负数,负数也可能移为正数。

数学意义:

  • 在没有数字溢出的前提下,左移1位相当于乘以2的1次方,左移n位相当于乘以2的n次方。

例:这里以-101(int类型)为例,负数在计算机内是以补码形式存储的,因此移位操作时也是在补码的基础上移位。

-101在计算机内的存储
源码 10000000 00000000 00000000 01100101
反码 11111111 11111111 11111111 10011010
补码 11111111 11111111 11111111 10011011

由补码可知,当向左移动到25、26、29位时-101变为正数,以下用程序来说明:

public class NumPlaceMove{
    public static void main(String[] args){
	int a = -101;
	for(int i=1;i<33;i++){
	    System.out.println(a+"<<"+i+"="+(a<<i));
	}
    }
}

 结果:

 

“有符号”右移操作符(>>):

value >> num     value指定移动的值  num指定移动的位数

运算规则:

  • 按照操作符右侧指定的位数将操作符左边的操作数向右移动(采用符号扩展机制);
  • 符号扩展进行移位,即:若符号为正,则在高位插入0,若符号为负,则在高位插入1(符号位保持不变);
  • 当左边的操作数为byte、short类型时,它们会被转换为int类型,其结果要是int类型。

数学意义:

  • 右移一位相当于除以2,右移n位相当于除以2的n次方。

例:-101(int类型32位)

-101右移2位内存分析
源码 1000,0000 0000,0000 0000,0000 0110,0101 取反----->
反码 1111,1111 1111,1111 1111,1111 1001,1010 加1 ----->
补码 1111,1111 1111,1111 1111,1111 1001,1011 >>2----->
移位后补码 1111,1111 1111,1111 1111,1111 1110,0110 减1----->
反码 1111,1111 1111,1111 1111,1111 1110,0101 取反----->
源码 1000,0000 0000,0000 0000,0000 0001,1010 十进制为:-26

值得注意的是:无论正负偶数左移一位直接是整除结果,但对于正值奇数结果是除以2后向下取整后的结果。

              对于负值奇数结果是除以2后向上取整结果。如下表:

  正数 负数
偶数(60) 直接除以2(30) 直接除以2(-30)
奇数(61) 除以2后向下取整(30) 除以2后向上取整(-31)

“无符号”右移操作符(>>>)

value >>> num     value指定移动的值  num指定移动的位数

运算规则:

  • 按照操作符右侧指定的位数将操作符左边的操作数向右移动(0扩展机制);
  • 移位过程中,无论数值是正数还是负数,都在最高位补0
  • 只对32位和64位值有意义

在Thinking in java 中有这么一句话:

只有数值右端的低5位才有用,这样可以防止我们移位超过int型值所具有的位数。(因为2的5次方为32,而int类型只有32位)若对一个long类型的数值进行处理,最后得到的结果也是long类型,此时只会用到数值右端的低6位,以防止移位超过long型数值具有的位数

换言之,如果移动位数超过该类型的最大位数,那么编译器会对移动的位数取模。例如果对int类型移位33位,实际上只移动了33%32=1位。具体细节是(int a<<b)如果移位超过数值类型的最大位数,就将b化为二进制数,取右端的低5位数,再把这5位数化为10进制,此时这个10进制就是要将a移动的位数,long 类型同理。

注意:移位运算符不存在“无符号”左移这一说。

猜你喜欢

转载自blog.csdn.net/qq_41892229/article/details/82874928