简介

一个数的最近2的幂次数,是java hashmap初始化方法指定容量里面对容量进行处理采用的方法

1.位运算符号介绍

符号 描述 运算规则
& 两个位都为1时,结果才为1
| 两个位都为0时,结果才为0
^ 异或 两个位相同为0,相异为1
~ 取反 0变1,1变0
<< 左移 各二进位全部左移若干位,高位丢弃,低位补0
>> 右移 各二进位全部右移若干位,对无符号数,高位补0,有符号数,各编译器处理方法不一样,有的补符号位(算术右移),有的补0(逻辑右移)
>>> 无符号右移 在右移的基础上,高位补0,无论有符号数还是无符号数
<<< 没有 没有无符号左移

2.JDK1.8中hashmap的tableSizeFor源码,如下

static final int tableSizeFor(int cap) {
int n = cap - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}

测试

    public static void main(String[] args) {
hightwo(0);
hightwo(7);
hightwo(32);
}
private static void hightwo(int cap) {
int n = cap - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
System.out.println((n<0) ? 1 : (n+1));
}

结果:

解析:计算容量,通过参数中指定的容量,得到离2的n次幂最近的数返回(数大于等于原来输入cap)

思路:先将cap的低位全变1,之后再+1,使低位进位变0,高位变1

举例cap为7    

cap:7 二进制 0000 0111
n cap-1 6 0000 0110
0000 0011 n>>>1
0000 0110 n
==================
0000 0111 n|n>>>1

0000 0001 n>>>2
0000 0111
==================
0000 0111 n|n>>>2 低位全为1,后续操作结果一样
...
n 0000 0111 7

cap = n+1 = 8

问题:关于为什么cap首先减1?

回答:防止本来就是2的次幂数返回2倍,比如cap是8,若不减1,则返回16而不是8了

举例

cap 8

0000 1000
0000 0100 n>>>1
===================
0000 1100 n|n>>>1

0000 0011 n>>>2
0000 1100
====================
0000 1111 n|n>>>2 低位全为1,后续操作结果一样
0000 0001 n+1
=====================
0001 0000 16
cap = 15 + 1 = 16

3.其它

一个数的最近2的幂次数(小于等于原数)

    private static int lowtwo(int n) {
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
n -= n>>>1;
return (n <= 0) ? 1 : n;
}

思路:将cap低位变1,再无符号右移1位,cap再减之,将低位变0,高位保留

测试

    public static void main(String[] args) {
System.out.println(lowtwo(0));
System.out.println(lowtwo(7));
System.out.println(lowtwo(32));
} private static int lowtwo(int n) {
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
n -= n>>>1;
return (n <= 0) ? 1 : n;
}

/*结果*/
1
4
32

关于JDK1.8 java HashMap的tableSizeFor的解析:一个数最近2的幂次数方法的更多相关文章

  1. 给jdk写注释系列之jdk1.6容器(5)-LinkedHashMap源码解析

    前面分析了HashMap的实现,我们知道其底层数据存储是一个hash表(数组+单向链表).接下来我们看一下另一个LinkedHashMap,它是HashMap的一个子类,他在HashMap的基础上维持 ...

  2. Java集合(七)--基于jdk1.8的HashMap源码

    HashMap在开发中经常用,面试源码方面也会经常问到,在之前也多次了解过源码,今天算是复习一下,顺便好好总结一下,包括在后面有 相关面试题.本文不会对红黑树代码由太多深入研究,特别是删除方面太复杂, ...

  3. 【JDK1.8】Java HashMap实现细节

    底层是用数组实现的 /** * The table, initialized on first use, and resized as * necessary. When allocated, len ...

  4. JAVA HashMap与ConcurrentHashMap

    HashMap Fast-Fail(遍历时写入操作异常) 在使用迭代器的过程中如果HashMap被修改,那么ConcurrentModificationException将被抛出,也即Fast-fai ...

  5. Java——HashMap底层源码分析

    1.简介 HashMap 根据键的 hashCode 值存储数据,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却是不确定的. HashMap 最多只允许一条记录的key为 nu ...

  6. Java——HashMap集合详解

    第一章 HashMap集合简介 1.1 介绍 HashMap基于哈希表的Map接口实现,是以key-value存储形式存在,即主要用来存放键值对.HashMap 的实现不是同步的,这意味着它不是线程安 ...

  7. JDK1.7中HashMap底层实现原理

    一.数据结构 HashMap中的数据结构是数组+单链表的组合,以键值对(key-value)的形式存储元素的,通过put()和get()方法储存和获取对象. (方块表示Entry对象,横排表示数组ta ...

  8. 十个问题带你了解和掌握java HashMap

    十个问题带你了解和掌握java HashMap 一.前言 本篇内容是源于 " 由阿里巴巴Java开发规约HashMap条目引发的故事",并在此基础上加了自己的对HashMap更多的 ...

  9. java HashMap源码分析(JDK8)

    这两天在复习JAVA的知识点,想更深层次的了解一下JAVA,所以就看了看JAVA的源码,把自己的分析写在这里,也当做是笔记吧,方便记忆.写的不对的地方也请大家多多指教. JDK1.6中HashMap采 ...

  10. Java泛型底层源码解析-ArrayList,LinkedList,HashSet和HashMap

    声明:以下源代码使用的都是基于JDK1.8_112版本 1. ArrayList源码解析 <1. 集合中存放的依然是对象的引用而不是对象本身,且无法放置原生数据类型,我们需要使用原生数据类型的包 ...

随机推荐

  1. shell_Day07

    函数: 函数介绍function 为了避免代码重复使用,我们一般通过函数编写代码块,而这一个代码块用来实现某种功能,这个功能在后面的代码中,会重复调用: 函数的语法格式 function check_ ...

  2. uni-app学习笔记之----传参、通讯

    1.页面传参 父级页面传递参数到详情页: 详情页得到参数: 打印: 2.组件通信 (1)子组件---->父组件:$emit() (2)父组件---->子组件:props (3)兄弟组件: ...

  3. 002. html篇之《表格》

    html篇之<表格> 1. 结构 <table> <!-- 表格标签 --> <caption>标题,自动居中对齐</caption> &l ...

  4. RocketMQ学习笔记

    RocketMQ学习笔记 RocketMQ学习参考官网文档:https://github.com/apache/rocketmq/tree/master/docs/cn . 由于RocketMQ是有国 ...

  5. i春秋云镜 CVE-2022-32991

    第一种方法 第二种延时注入

  6. SpringBoot为什么这么火?

    1.  总的设计原则是""默认大于配置"" 2. Starter机制,开箱即用,默认的配置和依赖都是默认加载的 3. SpringBoot是Spring的子类, ...

  7. C# const, readonly, static readonly

    转: Const 定义的是静态常在对象初始化的时候赋值.以后不能改变它的值.属于编译时常量.不能用new初始化. Readonly 是只读变量.属于运行时变量.可以在类constructor里改变它的 ...

  8. C#中socket的简单使用

    一.Socket的概念Socket其实并不是一个协议,而是为了方便使用TCP或UDP而抽象出来的一层,是位于应用层和传输控制层之间的一组接口. 当两台主机通信是,必须通过Socket连接,Socket ...

  9. iOS笔记 - Runtime 01:前期准备(isa结构 | Class结构 | 方法缓存)

    前言 1 - OC机制很多都是基于 Runtime实现的,比如指针的弱引用.OC的消息机制属于 Runtime的一部分 2 - OC是一门动态语言,在程序运行过程中就可以修改已经编译好的代码 3 -  ...

  10. rabbitMQ queue属性

    Map<String, Object> args = new HashMap<String, Object>(); args.put("x-message-ttl&q ...