商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > Java位运算左移右移详解:原码反码补码与无符号右移的区别

Java位运算左移右移详解:原码反码补码与无符号右移的区别

  发布于2026-07-24 阅读(0)

扫一扫,手机访问

位运算这块,很多人学的时候觉得概念太多,原码、反码、补码、左移右移,混在一起容易晕。但真正搞懂了,会发现它其实非常规整,而且很多底层框架都在用。我们先从几个容易让人困惑的点说起。

为什么没有无符号左移呢?

先问一个看似简单,但很多人不一定答得上来问题:为什么只有无符号右移(>>>),而没有无符号左移(<<<)?

答案其实很直接:左移操作本身就和符号位无关。在计算机里,位运算中的左移,最高位就是符号位,左移时,最高位直接就被丢弃了,低位补0。所以,不管符号位是什么,左移后它都会消失,不存在“保留符号位”或“不保留符号位”的选项。

Ja va位运算左移右移详解:原码反码补码与无符号右移的区别

举个例子,8位的byte类型,最高位如果是1,那它就表示负数。把它左移一位,结果就是:最高位的1被丢掉,最低位补0。比如 1111 1111 << 1 的结果是 1111 1110。所以,不只是Ja va,任何语言都没有“无符号左移”这个东西,因为技术上没有实现的必要。

位操作操作的是原码、反码还是补码?

这是一个很基础,但也很容易搞混的概念。原码、反码、补码,它们是同一种数字的不同“编码方式”。

  • 原码:最直观的表示。第一位是符号位(0正1负),后面跟着数值的绝对值。比如8位二进制里,+1原码是 0000 0001,-1原码是 1000 0001
  • 反码:正数的反码就是它自己;负数的反码,是在原码的基础上,符号位不变,其他位全部取反。所以+1的反码是 0000 0001,-1的反码是 1111 1110
  • 补码:正数的补码就是它自己;负数的补码,是在原码的基础上,符号位不变,其他位取反,然后加1。所以+1的补码是 0000 0001,-1的补码是 1111 1111

关键点:计算机内部,所有数字都是以补码的形式存储的。 这样做的好处是,可以把减法统一成加法来运算,简化电路设计,而且还能多表示一个最低数。比如8位二进制,原码和反码能表示的范围是[-127, +127],而补码能表示[-128, +127]。

左移 <<

左移的规则很简单:把二进制位整体向左移动,左边超出的部分直接丢弃,右边空出来的位置补0。这个过程不考虑符号位,因为符号位也会被移动和丢弃。

正数

以数字10为例,它的二进制补码是:

00000000 00000000 00000000 00001010

左移1位后,变成:

00000000 00000000 00000000 00010100

结果就是十进制20,相当于乘以2。HashMap在扩容时,将新容量设为旧容量的2倍,用的就是左移。

负数

以负数-10为例,它的二进制补码是:

1111 1111 1111 1111 1111 1111 1111 0110

左移1位后,变成:

1111 1111 1111 1111 1111 1111 1110 1100

结果是-20,同样是乘以2的效果。

右移 >>

右移和左移不同,它需要考虑符号位。规则是:把二进制位整体向右移动,左边空出来的位置,用原来的符号位来填充(正数补0,负数补1),右边超出的部分直接丢弃。

正数

以10为例:

00000000 00000000 00000000 00001010

右移1位后,变成:

00000000 00000000 00000000 00000101

结果是5,相当于除以2。ArrayList扩容时,将新容量增加为原来的1.5倍,用的就是右移。

负数

以负数-10为例:

1111 1111 1111 1111 1111 1111 1111 0110

右移1位后,左边补1:

1111 1111 1111 1111 1111 1111 1111 1011

结果是-5,也是除以2的效果。

无符号右移 >>>

无符号右移,顾名思义,就是不关心符号位,不管正数负数,左边空出来的位一律补0,右边超出的部分直接丢弃。

正数

结果和普通的右移完全一样,因为正数符号位就是0。

负数

以-10为例:

1111 1111 1111 1111 1111 1111 1111 0110

无符号右移1位后,左边补0:

01111 1111 1111 1111 1111 1111 1111 1011

结果变成了一个非常大的正数:2147483643。HashMap在计算一个数最接近的2的N次幂时,就大量使用了无符号右移。

超过32位的左移会怎样?

如果对一个int类型的数字左移超过32位,比如左移33位,实际效果等同于左移1位。右移和无符号右移同理。

a << n == a << (n % 32)

说白了,就是对位移的位数做了一个取模运算。这是一个很实用的底层细节。

总结

位运算看似复杂,但核心逻辑非常清晰。左移和右移,一个不管符号位,一个管符号位;无符号右移,则是对右移的一个补充,专门为了处理负数而设计。理解到位运算的底层逻辑,写代码时会更有底气,尤其是在阅读像HashMap、ArrayList这种核心源码时,会感觉豁然开朗。

本文转载于:https://www.jb51.net/program/367994k0w.htm 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注