understand java displacement operator

Reprinted from: https://www.cnblogs.com/winsker/p/6728672.html

 

    The object that the shift operator operates on is the binary bit, and the shift operator can be used alone to process the int type integer.

 operator       meaning       example      
<< Left shift operator, moves the object on the left side of the operator to the left by the number of bits specified on the right side of the operator (add 0 in the low order) x<<3
>> The "signed" right shift operator moves the object to the left of the operator to the right by the number of bits specified to the right of the operator. The sign extension mechanism is used, that is, if the value is positive, the high-order 0 is added, and if the value is negative, the high-order 1 is added. x>>3
>>> The "unsigned" right shift operator moves the object on the left side of the operator to the right by the number of bits specified on the right side of the operator. The 0 extension mechanism is adopted, that is, no matter the value is positive or negative, 0 is added to the high position. x>>>3

  

 

 

Taking 6297 of int type as an example, the code is as follows:

[java] view plaincopy
  1. System.out.println(Integer.toBinaryString(6297));   
  2. System.out.println(Integer.toBinaryString(-6297));   
  3. System.out.println(Integer.toBinaryString(6297>>5));   
  4. System.out.println(Integer.toBinaryString(-6297>>5));   
  5. System.out.println(Integer.toBinaryString(6297>>>5));   
  6. System.out.println(Integer.toBinaryString(-6297>>>5));   
  7. System.out.println(Integer.toBinaryString(6297<<5));   
  8. System.out.println(Integer.toBinaryString(-6297<<5));  

 

  operation result:

1100010011001
11111111111111111110011101100111
11000100
11111111111111111111111100111011
11000100
111111111111111111100111011
110001001100100000
11111111111111001110110011100000

Note: x<<y is equivalent to x*2 ; x>>y is equivalent to x/2 y
    In terms of calculation speed, shift operations are faster than arithmetic operations.
    If x is negative, then x>>>3 has no arithmetic meaning, only logical meaning.

 

There is such a passage in Think in  Java

"Shift char, byte or short, then they are automatically converted to an int before the shift is performed. Only the 5 low-order bits on the right side are useful. This prevents us from shifting in an int number. The actual number of bits. If a long value is processed, the final result is also a long. At this time, only the 6 low-order bits on the right side are used to prevent moving more than the ready-made number of bits in the long value."

 

这段话有两个出处,一个是Java编程思想3.11移位操作符中出现,原话是“只有数值右端的低5位才有用”。一个是Java解惑中谜题27:变幻莫测的i值,原话是“移位操作符只使用其右操作数的低5位作为移位长度”。

弄清这句话首先需要弄清楚移位操作符,移位操作符是一个二元操作符,两个操作数分别位于移位操作两边形如:左操作数 移位操作符 右操作数 这样的结构,其含义是,将左操作数按照移位操作符指定的移位方向,进行右操作数指定的次数的移位。然后对照出处二,Java解惑中所描述的,就豁然开朗了。

首先,移位操作符能操作的数只有int类型和long类型,这个是指左操作数的类型。对于int类型而言,int在Java中占4字节,一共32位,也就是说,对于一个在Java中的int数据,做32次移位,那么这个int数据就完全变了,以左移为例,左移是补0,那么对于任意一个int类型数据,做32次移位,那么int数据变成32位全0的数据,Java不允许一次性移位左操作数的所有位,也就是右操作数不能大于32。于是回到上述的句子,其指的是右操作数的低5位,5位二进制所代表的最大值为2^5-1,为31,所以取右操作数的低5位,就是只看右操作数的二进制的低5位,其数值不会超过2^5次方,也就是int的32位。因此,移位操作符进行移位的实际次数,其实是右操作数2的次数。


对上面那段话的理解是:移位操作符操作的运算对象是二进制的“位”,int类型是32位也就是2的5次幂 !如果移32位以上,那么原来的数的信息会全部丢失,这样也就没有什么意义了!所以上面的“只有右侧的5个低位才会有用”说的是:移位操作符右端的那个数(化成二进制)的低5位才有用,即
X < <y;

是指y的低5位才有用,即不能大于32。 而对于long型也是同样的道理!

因此,如果对一个int 型,进行移位,X < <y; 当y小于32时,移位后的结果一般都在我们的预料当中;而如果y大于32时,由于移位超出了int所能表示的范围,这时就先把y化成二进制数,然后取该二进制数右端的低5位,再把这5位化成十进制,此时的这个十进制就是要对X移动的位数。
例如:

int int a=140;
a << 34
System.out.println(Integer.toBinaryString(a << b));

上面那两个语句的执行过程是:先把a化成二进制数:10001100

执行语句 a << 34 对a左移32位时,先把 34化成二进制:100010,对该二进制数取右边5位,即00010,化成十进制数为2,所以实际上是对a左移两位。现在,地球人都会知道上面程序的输出结果是:1000110000

//////////////////////////////////////////////////
移位运算符和按位运算符一样,同属于位运算符,因此移位运算符的位指的也是二进制位。它包括以下几种:
左移位(<<):将操作符左侧的操作数向左移动操作符右侧指定的位数 。移动的规则是在二进制的低位补0。

有符号右移位(>>):将操作符左侧的操作数向右移动操作符右侧指定的位数。移动的规则是,如果被操作数的符号为正,则在二进制的高位补0;如果被操作数的符号为负,则在二进制的高位补1。

无符号右移位(>>>):将操作符左侧的操作数向右移动操作符右侧指定的位数。移动的规则是,无论被操作数的符号是正是负,都在二进制位的高位补0。
注意,移位运算符不存在“无符号左移位(<<<)”一说。与按位运算符一样,移位运算符可以用于byte、short、int、long等整数类型,和字符串类型char,但是不能用于浮点数类型float、double;当然,在Java5.0及以上版本中,移位运算符还可用于byte、short、int、long、char对应的包装器类。我们可以参照按位运算符的示例写一个测试程序来验证,这里就不再举例了。
与按位运算符不同的是,移位运算符不存在短路不短路的问题。
写到这里就不得不提及一个在面试题中经常被考到的题目:

请用最有效率的方法计算出2乘以8等于几?这里所谓的最有效率,实际上就是通过最少、最简单的运算得出想要的结果,而移位是计算机中相当基础的运算了,用它来实现准没错了。左移位“<<”把被操作数每向左移动一位,效果等同于将被操作数乘以2,而2*8=(2*2*2*2),就是把2向左移位3次。因此最有效率的计算2乘以8的方法就是“2<<3”。

最后,我们再来考虑一种情况,当要移位的位数大于被操作数对应数据类型所能表示的最大位数时,结果会是怎样呢?比如,1<<35=?呢?
这里就涉及到移位运算的另外一些规则:
byte、short、char在做移位运算之前,会被自动转换为int类型,然后再进行运算。 byte、short、int、char类型的数据经过移位运算后结果都为int型。 long经过移位运算后结果为long型。

在左移位(<<)运算时,如果要移位的位数大于被操作数对应数据类型所能表示的最大位数,那么先将要求移位数对该类型所能表示的最大位数求余后,再将被操作数移位所得余数对应的数值,效果不变。

比如1<<35=1<&lt;(352)=1<<3=8。 对于有符号右移位(>>)运算和无符号右移位(>>>)运算,当要移位的位数大于被操作数对应数据类型所能表示的最大位数时,那么先将要求移位数对该类型所能表示的最大位数求余后,再将被操作数移位所得余数对应的数值,效果不变。。

比如100>>35=100>>(352)=100>>3=12。

另:

Java 的 Integer.toBinaryString 方法

复制代码
public static String toBinaryString(int i)

    //以二进制(基数 2)无符号整数形式返回一个整数参数的字符串表示形式。 
    //如果参数为负,该无符号整数值为参数加上 2^32;否则等于该参数。

        System.out.println(Integer.toBinaryString(-1)) ;
        System.out.println(Integer.toBinaryString(2)) ;
        System.out.println(Integer.toBinaryString(1)) ;
复制代码
    输出:
        11111111111111111111111111111111
        11111111111111111111111111111110
        1

结论输出的是数字的二进制补码。为什么说是以 二进制无符号整数形式 返回一个 整数类型的字符串,为什么 如果参数为负数,就要加上 232 次方?

因为Java里的int是有符号的,在内存中没有正负之分,只有0/1,整数是用补码表示的

正数补码等于原码
负数的补码等于其绝对值的反码+1,正好等于自身+2^32(对于4字节的整型来说)

-1 的补码 就是 绝对值1 的反码(按位取反) 11111111 11111111 11111111 11111110 再+1
等于 11111111 11111111 11111111 11111111

这样正好能把最高位为1的数字用来表示负数,而最高位为0的数字表示非负数

10000000 00000000 00000000 00000000 => -2147483648
11111111 11111111 11111111 11111111 => -1
00000000 00000000 00000000 00000000 => 0
00000000 00000000 00000000 00000001 => 1
01111111 11111111 11111111 11111111 => 2147483647

因此负数+2^32之后的二进制串,就是该负数内存中准确的存储形式

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326261347&siteId=291194637