您的位置  > 互联网

关于移位(Shift)操作符,你只知道一些基本概念

移位(Shift)运算符是最基本的运算符之一,几乎每种编程语言中都包含该运算符。

同时,我们对轮班操作感到陌生和困惑。 这是因为你不仅会在JDK底层遇到很多移位操作,在各种奇奇怪怪的面试题中也会遇到很多移位操作。 在实际使用中,你会遇到一些移位操作。 有时候,这个操作其实很难用。

因为用得不多,所以大多数人在面对的代码中根本不会考虑移位操作,所以我们只需要对移位操作有一个大概的了解即可。 至于奇怪的操作,你只需要了解一些基本概念就足够了。 事实上,很多时候不需要直接使用移位运算来计算。

基本概念

对于班次操作,我们需要了解几个基本概念。

3 名轮班操作员

Java 只有 3 个移位运算符,(有符号右移)和 >>>(无符号右移)。

为什么有3个? 移位操作可以是左移或右移。 为什么有3个?

因为Java的整数是有符号整数,所以Java添加了无符号右移来进行符号转换。

只能用于整数

Java的移位运算不能用于浮点数,只能用于整数。

由于Java可以处理不同长度的整数,因此移位操作仅适用于整数。 虽然也可以使用其他数据类型,但它们是在转换为整数后计算的。

类型

长度

长的

64位

整数

32位

短的

16位

字节

8位

字符

16位

整数二进制表达式

在Java的整数表达式中,为符号位置保留了1位,因此实际可以存储数据的位数为31位。

因此,Int的存储范围是:[-2^31,2^31-1],所以上面的索引是31,而不是32,因为符号位还剩下一位。

左移运算符是有符号右移运算符。 将数据转换为二进制数后,它会向右移动一些位。 高位用符号位补充,低位被丢弃。

当对正数进行右移操作时,具体实施例是将高位补0; 负数则填1

这主要是因为向右移动时高位出现缺口时,我们还是应该补0或1的问题。

有符号右移的意思是:当高位为空时,我们填充符号位,符号位根据当前数据而变化。

比如下面的代码:

log.debug("{}", Integer.toBinaryString(-12));
        log.debug("{}", Integer.toBinaryString(-12 >> 1));
        log.debug("{}", Integer.toBinaryString(-12 >> 8));

运行结果为:

12:25:32.765 [main] DEBUG com.ossez.toolkits.codebank.tests.EmptyQuickTest - 11111111111111111111111111110100
12:25:32.765 [main] DEBUG com.ossez.toolkits.codebank.tests.EmptyQuickTest - 11111111111111111111111111111010
12:25:32.765 [main] DEBUG com.ossez.toolkits.codebank.tests.EmptyQuickTest - 11111111111111111111111111111111

我们可以看到,上面的移位是有符号移位位,所有移位的高位在为负时都补充为符号位。

如果是负数则补1。

无符号右移运算符>>>

无符号右移运算符 >>> 与 >> 类似。 它们将数据转换为二进制数,然后将其右移若干位。 不同的是,无论是否为负数,结果都是将高位补零,丢弃低位。

由于补码的不同,该运算符的计算会将负数变成整数。

比如下面的代码。

log.debug("---- Shift Operator >>> ---");
        log.debug("{}", Integer.toBinaryString(-12));
        log.debug("{}/{}", Integer.toBinaryString(-12 >>> 1), Integer.parseInt(Integer.toBinaryString(-12 >>> 1), 2));
        log.debug("{}/{}", Integer.toBinaryString(-12 >>> 8), Integer.parseInt(Integer.toBinaryString(-12 >>> 8), 2));

程序输出如下:

13:25:19.374 [main] DEBUG com.ossez.toolkits.codebank.tests.EmptyQuickTest - ---- Shift Operator >>> ---
13:25:19.374 [main] DEBUG com.ossez.toolkits.codebank.tests.EmptyQuickTest - 11111111111111111111111111110100
13:25:19.374 [main] DEBUG com.ossez.toolkits.codebank.tests.EmptyQuickTest - 1111111111111111111111111111010/2147483642
13:25:19.374 [main] DEBUG com.ossez.toolkits.codebank.tests.EmptyQuickTest - 111111111111111111111111/16777215

从上面的代码输出中,我们会发现对应的二进制长度不同,因为在对于二进制的Java程序中,当前面为0时,输出时会被丢弃。

因此,显示的长度不同。 如果希望显示的长度一致,只需在前面加0即可。