Integer.highestOneBit(int i)方法的作用与底层实现
在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-1
i |= (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-1
i |= (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
Integer.highestOneBit(int i)方法的作用与底层实现的更多相关文章
- 详解Integer.toString(int i)方法和String.valueOf(int i)方法
通过查看String类的源码: public static String valueOf(int i) { return Integer.toString(i); } 我们可以看到,String.va ...
- integer与int区别以及integer.values()方法详解
声明:本文为博主转载文章,原文地址见文末. 知识点1:integer和int的区别 /* * int是java提供的8种原始数据类型之一.Java为每个原始类型提供了封装类,Integer是java为 ...
- Integer类toString(int i,int radix)方法
Integer类toString(int i,int radix)方法: 首先抛出java的api中的介绍: public static String toString(int i, int radi ...
- Integer 与 int -- 自动装箱(autoboxing)与自动拆箱(unboxing)
转载于 http://www.ticmy.com/?p=110 jdk1.5引入了自动装箱(autoboxing)与自动拆箱(unboxing),这方便了集合类以及一些方法的调用,同时也使初学者对其感 ...
- equal(),hashcode(),toString()方法的作用
equal(),hashcode(),toString()方法的作用 这三个方法都是java.lang.Object的方法. equal();判断两对象是否相等hashcode();为对象在容器中添加 ...
- 区分Integer.getInteger和Integer.valueOf、Integer.parseInt() 的使用方法
Integer类有两个看起来很类似的静态方法,一个是Integer.getInteger(String),另外一个是Integer.valueOf(String).如果只看方法名称的话,很容易将这两个 ...
- java克隆对象clone()的使用方法和作用
转自:997.html">http://www.okrs.cn/blog/news/?997.html 内容摘要 若需改动一个对象,同一时候不想改变调用者的对象.就要制作该对象的一个本 ...
- 你知道Object中有哪些方法及其作用吗?
一.引言二.Object方法详解1.1.registerNatives()1.2.getClass()1.2.1.反射三种方式:1.3.hashCode()1.4.equals()1.4.clone( ...
- Object中有哪些方法及其作用
你知道Object中有哪些方法及其作用吗? 一.引言 二.Object方法详解 1.1.registerNatives() 1.2.getClass() 1.2.1.反射三种方式: 1.3.hashC ...
随机推荐
- python zlib模块缺失报错:RuntimeError: Compression requires the (missing) zlib module
解决方式: # yum install zlib # yum install zlib-devel 下载成功后,进入python2.7的目录,重新执行 #make #make install 此时先前 ...
- 基于思岚A1激光雷达+OpenGL+VS2017的Ramer-Douglas-Peucker算法的实现
时隔两年 又借到了之前的那个激光雷达,最老版本的思岚A1,甚至不支持新的固件,并且转接板也不见了,看了下淘宝店卖¥80,但是官方提供了一个基于STM32的实现方式,于是我估摸着这个转接板只是一个普通的 ...
- (尚023)Vue_案例_交互添加
最终达到效果: 1.做交互,首先需要确定操作哪个组件? 提交------操作组件Add.vue 2.从哪开始做起呢? 从绑定事件监听开始做起,确定你跟谁绑定事件监听,在回调函数中做什么, ====== ...
- div+css制作哆啦A梦
纯CSS代码加上 制作动画版哆啦A梦(机器猫) 哆啦A梦(机器猫)我们大家一定都很熟悉,今天给大家演示怎么用纯CSS.代码,来做一个动画版的哆啦A梦. 效果图: 下面代码同学可以查看一下,每个线条及椭 ...
- linux命令之------Chmod命令
Chmod命令 1)作用:linux和unix的文件调用权限分为三级:文件拥有者/群组/其他.利用chmod可以控制文件如何被他人所调用.(主要就是修改文件夹,文件的权限) 2)U表示该文件的拥有者, ...
- vue-cli使用笔记
安装nodejs 安装vue-clinpm install -g vue-cli 使用vue-cli初始化项目vue init webpack my-project 进到目录cd my-project ...
- js中forEach,for in,for of循环的用法详解
一.一般的遍历数组的方法: var array = [1,2,3,4,5,6,7]; for (var i = 0; i < array.length; i) { console.log(i,a ...
- java基础-数据输入
import java.util.Scanner; public class ScannerTest { public static void main(String[] args) { //身高未知 ...
- 第12组 Beta版本演示
前言 组长博客 组名: To Be Done 组员和贡献比例 短学号 姓名 分工 贡献比例 614 王永福* 前后端实现.发任务.催进度 30% 440 孙承恺 UI设计 15% 529 邱畅杰 文本 ...
- hadoop jps不显示信息
使用kvm做了一个hadoop组件的镜像,使用该镜像启动,在使用jps的时候,没有任何信息显示. 解决: 删除/tmp下的hsper开头文件,哪个用户没有权限就删除对应的hsper**_usernam ...