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

 更新时间:2026年07月24日 09:29:48   作者:Masked5  
这篇文章详细解释了为什么没有无符号左移运算符,并深入讲解了原码、反码和补码的区别,以及计算机为何使用补码存储数字,通过正负数示例,清晰展示了左移、右移和无符号右移的运算规则,还结合HashMap和ArrayList扩容源码,帮你轻松掌握位运算在实际开发中的应用

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

在计算机中,位运算中左移跟符号没有关系的,因为最高位就是符号位。

例如8位的byte中最高位如果是1那就表示负数。如果是左移一位,那么最高位就会丢掉,最低位补0。

例如:1111 1111 << 1 就会变成 1111 1110。因此,不仅是Java,任何语言都没有无符号左移运算符。

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

原码、反码和补码都是用来表示数字的编码方式。

  • 原码就是符号位加上真值的绝对值,即用第一位表示符号,其余位表示值。例如,如果是8位二进制,那么+1的原码为0000 0001,-1的原码为1000 00011。
  • 反码的表示方法是:正数的反码是其本身;负数的反码是在其原码的基础上,符号位不变,其余各个位取反。例如,+1的反码为0000 0001,-1的反码为1111 11101。
  • 补码的表示方法是:正数的补码就是其本身;负数的补码是在其原码的基础上,符号位不变,其余各位取反,最后+1。例如,+1的补码为0000 0001,-1的补码为1111 11111。

计算机内部使用补码来存储数字。这样做可以简化计算机底层电路设计,并且可以多表示一个最低数。例如,在8位二进制中,使用原码或反码表示时范围为[-127, +127],而使用补码表示时范围为[-128, +127]。

左移 <<

将一个数对应的二进制表示整体左移,不考虑符号位,左边超出的部分舍弃,右边补零。

正数

以数字10为例,二进制表示为

00000000 00000000 00000000 00001010

第一位为符号位,0表示正数,1表示负数。左移1位之后为

00000000 00000000 00000000 00010100

十进制表示为20,相当于乘以2。HashMap扩容时将新容量增加为原来容量的两倍,就是使用左移实现的。

负数

以负数-10为例,二进制表示为

1111 1111 1111 1111 1111 1111 1111 0110

左移1位结果为

1111 1111 1111 1111 1111 1111 11110 1100

十进制为-20,也是相当于乘以2。

右移 >>

将一个数对应的二进制表示整体右移,考虑符号位,左边的用原有符号位补充,右边超出的部分舍弃。

正数

以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位

1111 1111 1111 1111 1111 1111 1111 1011

十进制表示为-5,也是相当于除以2。

无符号右移 >>>

将一个数的二进制表示整体右移,不考虑符号位,左边部分总是以0填充,右边部分舍弃。

正数

和上面的右移一致。

负数

以-10为例

1111 1111 1111 1111 1111 1111 1111 0110

无符号右移1位

01111 1111 1111 1111 1111 1111 1111 1011

十进制表示为2147483643。HashMap中在求一个数最接近的2的N次幂时使用到了无符号右移。

超过32位的左移会怎样?

如果一个int型数字左移超过32位,如33位,相当于左移1位,右移、无符号右移同理。

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

位移是一个取模的过程

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • JAVA IO的3种类型区别解析

    JAVA IO的3种类型区别解析

    这篇文章主要介绍了JAVA IO的3种类型解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-10-10
  • 在springboot项目中同时接收文件和多个参数的方法总结

    在springboot项目中同时接收文件和多个参数的方法总结

    在开发接口中,遇到了需要同时接收文件和多个参数的情况,可以有多种方式实现文件和参数的同时接收,文中给大家介绍了两种实现方法,感兴趣的同学跟着小编一起来看看吧
    2023-08-08
  • Java调用通义千问API的详细步骤

    Java调用通义千问API的详细步骤

    这篇文章主要介绍了在Java中接入通义千问API的步骤,包括获取APIKey、添加依赖、配置模型和流式响应等,并提供了响应处理和高级功能实现示例,以及常见问题解决方案,需要的朋友可以参考下
    2026-03-03
  • MyBatis编写一个简单的SQL生成工具

    MyBatis编写一个简单的SQL生成工具

    MyBatis 是一个强大的数据持久化框架,它提供了一种半自动化的 ORM 实现方式,本文将为大家介绍如何使用MyBatis编写一个简单的SQL生成工具,需要的可以了解下
    2025-03-03
  • SpringBoot集成JWT无状态身份认证的方案详解

    SpringBoot集成JWT无状态身份认证的方案详解

    本文介绍了如何在SpringBoot项目中集成JWT实现无状态身份认证,JWT由Header、Payload和Signature三部分组成,通过添加JJWT依赖,创建JWT工具类和认证拦截器,实现前后端的交互流程,需要注意安全性、性能优化和常见问题,感兴趣的朋友跟随小编一起看看吧
    2025-11-11
  • Java8如何构建一个Stream示例详解

    Java8如何构建一个Stream示例详解

    Java 8 是迄今为止在语义上改动上最大的一个平台。下面这篇文章主要给大家介绍了关于Java8如何构建一个Stream的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧。
    2018-04-04
  • 一篇文章带你搞定JAVA注解

    一篇文章带你搞定JAVA注解

    这篇文章主要介绍了详解Java注解的实现与使用方法的相关资料,希望通过本文大家能够理解掌握Java注解的知识,需要的朋友可以参考下
    2021-07-07
  • 详解如何在Java中实现屏幕共享

    详解如何在Java中实现屏幕共享

    在本文中,将为大家展示如何利用 JxBrowser 的功能,实现运行在不同电脑上的两个 Java 应用程序之间的屏幕共享,感兴趣的小伙伴可以参考一下
    2024-10-10
  • Java编写网上超市购物结算功能程序

    Java编写网上超市购物结算功能程序

    这篇文章主要为大家详细介绍了Java编写网上超市购物结算功能程序的具体代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-06-06
  • 详解Java线程池的使用(7种创建方法)

    详解Java线程池的使用(7种创建方法)

    这篇文章主要介绍了详解Java线程池的使用(7种创建方法),线程池的创建⽅式总共包含7种,其中6种是通过Executors创建的,1种是通过ThreadPoolExecutor创建的,今天我们就来详细说一下
    2023-03-03

最新评论