Java位运算左移右移原码反码补码与无符号右移区别详解
Java位运算涉及原码、反码、补码及左移右移操作,概念易混淆但结构规整,底层框架频繁使用。其中无符号右移(>>>)存在,而无符号左移因左移时符号位不变而缺失,此差异值得深入思考。
位运算这块,很多人初学时容易混淆概念,比如原码、反码、补码、左移右移等,很容易让人感到困惑。但其实一旦真正理解,你会发现它的逻辑非常清晰,而且许多底层框架中都有广泛应用。我们先从几个容易让人产生疑问的点开始讲解。
为什么没有无符号左移呢?
首先提出一个看似简单,但很多人不一定能答得上来的问题:为什么只有无符号右移(>>>),而没有无符号左移(<<<)?
答案其实非常直接:左移操作本身就和符号位无关。在计算机内部,位运算中的左移,最高位本身就是符号位,左移时最高位直接就被丢弃了,低位补0。因此,无论符号位是什么,左移后它都会消失,根本不存在“保留符号位”或“不保留符号位”的选项。

举例来说,8位的byte类型,如果最高位是1,就表示负数。将其左移一位,结果就是:最高位的1被丢弃,最低位补0。例如 1111 1111 << 1 的结果是 1111 1110。因此,不只是Java,任何编程语言都没有“无符号左移”这个操作,因为技术上根本没有实现的必要。
位操作操作的是原码、反码还是补码?
这是一个非常基础,但也很容易混淆的概念。原码、反码、补码,它们是同一种数字的不同“编码方式”。
- 原码:最直观的表示。第一位是符号位(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这种核心源码时,会感觉豁然开朗。
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
面向对象编程:继承与方法重写入门教程:核心概念、操作步骤与结果验证
从父类与子类的关系入手,理解继承、方法重写和多态的基本机制,通过完整代码示例完成继承结构创建、方法重写与运行验证,并梳理常见错误和使用注意事项。
Python应用打包与部署入门教程:核心概念、操作步骤与结果验证
从 Python 应用打包的基本概念入手,介绍项目环境准备、依赖管理、构建发布包、安装部署以及运行结果验证,并梳理常见打包失败与部署问题,帮助初学者完成从源码到可部署应用的完整流程。
Python CLI 开发避坑指南:从环境配置到参数解析的实战排查
本文聚焦 Python 命令行工具(CLI)开发中最高频的故障点,按执行链路梳理从环境配置、参数解析、路径处理到异常调试的完整排查流程。通过具体代码示例与终端输出对照,提供可复现的修复方案,帮助开发者快速定位 ModuleNotFoundError、参数校验失败及跨平台兼容性问题,构建更健壮的命令行
Python CLI 开发:从参数解析到工程化发布的完整路径
本文以 Python 命令行工具开发为切入点,从项目结构搭建与虚拟环境配置入手,深入讲解 argparse 参数解析与子命令设计。通过一个完整的日志分析工具案例,演示输入校验、错误处理与异常捕获的最佳实践,最后覆盖打包发布流程与常见排查技巧,帮助开发者构建健壮、易用的 CLI 应用。
Python 模块与包的工程化实践:结构、依赖与排错指南
本文从项目目录规范与模块导入机制切入,详细阐述虚拟环境的配置、第三方包的管理策略以及完整案例的模块化拆分方法。通过具体代码示例展示如何构建高内聚低耦合的代码结构,并针对 ModuleNotFoundError、ImportError 及依赖冲突等常见工程问题提供系统化的排查与解决方案,帮助开发者建立
- 热门数据榜
1
2
3
4
5
6
7
8
9
10
相关攻略
2026-10-08 18:33
2026-10-01 18:40
2026-10-01 18:35
2026-10-01 18:30
2026-10-01 18:25
2026-10-01 18:20
2026-10-01 18:15
2026-10-01 18:10
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程

