在Integer类中有这么一个方法,你可以给它传入一个数字,它将返回小于等于这个数字的一个2的幂次方数。这个方法就是highestOneBit(int i)。

比如下面的Demo,注意方法的输入与返回值:

System.out.println(Integer.highestOneBit(15));  // 输出8
System.out.println(Integer.highestOneBit(16));  // 输出16
System.out.println(Integer.highestOneBit(17));  // 输出16

这个方法的实现代码量也是非常少的:

public static int highestOneBit(int i) {// HD, Figure 3-1i |= (i >>  1);i |= (i >>  2);i |= (i >>  4);i |= (i >>  8);i |= (i >> 16);return i - (i >>> 1);
}

接下来,我们就来详细分析一下这块代码的逻辑。

首先,对于这个方法的功能:给定一个数字,找到小于或等于这个数字的一个2的幂次方数。

如果我们要自己来实现的话,我们需要知道:怎么判断一个数字是2的幂次方数。

说真的,我一下想不到什么好方法来判断,唯一能想到的就是一个数字如果把它转换成二进制表示的话,它会有一个规律:如果一个数字是2的幂次方数,那么它对应的二进制表示仅有一个bit位上是1,其他bit位全为0。
比如:
十进制6,二进制表示为:0000 0110
十进制8,二进制表示为:0000 1000
十进制9,二进制表示为:0000 1001
所以,我们可以利用一个数字的二进制表示来判断这个数字是不是2的幂次方数。关键代码怎么实现呢?去遍历每个bit位?可以,但是不好,那怎么办?我们还是回头仔细看看Integer是如何实现的吧?

public static int highestOneBit(int i) {// HD, Figure 3-1i |= (i >>  1);i |= (i >>  2);i |= (i >>  4);i |= (i >>  8);i |= (i >> 16);return i - (i >>> 1);
}

我们发现这段代码中没有任何的遍历,只有位运算与一个减法,也就是说它的实现思路和我们自己的实现思路完全不一样,它的思路就是:给定一个数字,通过一系列的运算,得到一个小于或等于该数字的一个2的幂次方数。

也就是:如果给定一个数字18,通过运算后,要得到16。

18用二进制表示为: 0001 0010

想要得到的结果(16)是:0001 0000

那么这个运算的过程无非就是将18对应的二进制数中除最高位的1之外的其他bit位都清零,则拿到了我们想要的结果。

那怎么通过位运算来实现这个过程呢?

我们拿18对应的二进制数0001 0010来举个例子就行了:
先将0001 0010右移1位,
得到0000 1001,再与自身进行或运算:
得到0001 1011

再将0001 1011右移2位,
得到0000 0110,再与自身进行或运算:
得到0001 1111

再将0001 1111右移4位,
得到0000 0001,再与自身进行或运算:
得到0001 1111

再将0001 1111右移8位,
得到0000 0000,再与自身进行或运算:
得到0001 1111

再将0001 1111右移16位,
得到0000 0000,再与自身进行或运算:
得到0001 1111

再将0001 1111无符号右移1位,
得到0000 1111

关于无符号右移,可以看我之前写的文章。

最后用0001 1111 - 0000 1111 = 0001 0000
震惊!得到了我们想要的结果。

其实这个过程可以抽象成这样:
现在有一个二进制数据,0001****,我们不关心低位的取值情况,我们对其进行右移并且进行或运算。

先将0001****右移1位,
得到00001***,再与自身进行或运算:
得到00011***

再将00011***右移2位,
得到0000011*,再与自身进行或运算:
得到0001111*

再将0001111*右移4位,
得到00000001,再与自身进行或运算:
得到00011111

后面不用再推算了,到这里我们其实可以发现一个规律:
右移与或运算的目的就是想让某个数字的低位都变为1,再用该结果 减去 该结果右移一位后的结果,则相当于清零了原数字的低位。即得到了我们想要的结果。

到此,只能感叹JDK作者对于位运算的使用已经达到了出神入化的境界了。

如果想学习更多的精彩的Java、分布式、微服务等方面的知识,请关注微信公众号:1点25

转载于:https://www.cnblogs.com/nicerblog/p/11431181.html

Integer.highestOneBit(int i)方法的作用与底层实现相关推荐

  1. Java Integer类highestOneBit()方法与示例

    整数类highestOneBit()方法 (Integer class highestOneBit() method) highestOneBit() method is available in j ...

  2. Java黑皮书课后题第5章:**5.37(十进制转二进制)编写程序,提示用户输入一个十进制整数,然后显示对应的二进制值(不要使用Integer.toBinaryString(int)方法)

    5.37(十进制转二进制)编写程序,提示用户输入一个十进制整数,然后显示对应的二进制值 题目 题目概述 破题 代码 运行示例 题目 题目概述 5.37(十进制转二进制)编写程序,提示用户输入一个十进制 ...

  3. int 和 Integer有什么区别,Integer 有哪些函数方法

    [基本数据类型对象包装类JDk1.5以后的新特性]--[自动拆箱,装箱] 简化书写. Integer i = new Integer(5); 基本数据类型对象包装类,对象创建的简化写法Integer ...

  4. java关于Integer和int的区别以及equals()方法

    Integer和int的比较详解 https://blog.csdn.net/andyzhaojianhui/article/details/84324466 equals()方法用于判断参数的类型和 ...

  5. Java之String系列--intern方法的作用及原理

    原文网址:Java之String系列--intern方法的作用及原理_IT利刃出鞘的博客-CSDN博客 简介 本文介绍Java的String的intern方法的原理. 常量池简介 在 JAVA 语言中 ...

  6. java中 Integer.parseInt()和Integer.valueOf(“str”).intValue()方法的应用

    parseInt(String s )方法是类Integer的静态方法,它的作用就是将形参 s 转化为整数,比如: Interger.parseInt("1")=1; Intege ...

  7. Integer 和 int 比较的特殊之处

    2019独角兽企业重金招聘Python工程师标准>>> 第一个例子:  假设我们同时定义  int a = 3;  int b = 3; 编译器先处理int a = 3: 首先它会在 ...

  8. (备忘)Java数据类型中String、Integer、int相互间的转换

    1.Integer转换成int的方法 Integer i; int k = i.intValue(); 即Integer.intValue(); 2.int转换成Integer int i; Inte ...

  9. Java数据类型中String、Integer、int相互间的转换

    1.Integer转换成int的方法 Integer i;  int k = i.intValue(); 即Integer.intValue(); 2.int转换成Integer int i; Int ...

最新文章

  1. php api 20121113,php添加gd
  2. [bzoj1025][SCOI2009]游戏 (分组背包)
  3. 8086汇编 贪吃蛇 源代码
  4. java File文件路径获取的几种方法
  5. ASP.NET Core WebApi使用Swagger生成api说明文档看这篇就够了
  6. SpringBoot2.0 基础案例(10):整合Mybatis框架,集成分页助手插件
  7. 芝麻当家运营级商城源码/H5/小程序/网页
  8. 在 IntelliJ IDEA 中定制开发 ZooKeeper
  9. STM32F0xx_FLASH编程(片内)配置详细过程
  10. 美国当地时间4月17日中国概念股收盘行情
  11. invocation, 作者 Medwyn Goodall,女巫医 [搜索 invocation Medwyn Goodall]
  12. CLodop云打印服务(localhost本地)未安装启动
  13. php fakepath,在文件上载中获取真实路径而不是“fakepath”
  14. 骑行日志2011滇藏珠峰尼泊尔青藏 - 记那些逝去的青春
  15. 刚学的一招呵呵,愚人节到了,教个大家最强的整人方法
  16. 厚度仅2.5毫米,重60克,英伟达斯坦福做出了超轻薄VR眼镜
  17. 手机浏览器下载IOS版APP
  18. adobe cs4系列套装及注册机下载
  19. Android百度语音集成——文字转语音
  20. RabbitMQ的安装与配置

热门文章

  1. cmake qt 添加路径 项目_CMake配置Qt工程
  2. linux下代码写错了怎么更改_AWS全面上市开源Linux发行版,专为容器操作系统设计...
  3. 计算机一级ie浏览器和电子邮件,2016年职称计算机考试Internet基础知识:利用IE收发电子邮件...
  4. pythonxml解析拿到控件坐标_Python解析xml中dom元素的方法
  5. Linux命令之find的用法
  6. SpringSpringMVCMybatis框架-张晨光-专题视频课程
  7. java动态加载jar文件并执行方法
  8. 把字符串中的数字找出来并按照升序排序
  9. kafka集群操作指南
  10. mysql使用过程中的几个细节注意点