Map是开发中常用的数据结构之一,本系列文章根据源码一步步解析HashMap的工作原理,本文介绍HashMap中涉及的hash算法、求2的幂、红黑树。
环境介绍
- java 1.8.0_181
- Win 10
- Intellij IDEA
Hash算法
数据结构-散列表。HashMap中的hash算法在Object.hashCode的基础上进行了优化。
static final int hash(Object key) {
int h;
//1.获取hash code
//2.高16位与低16位按位异或
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
关于hash运算的方法,源码注释已做说明,简而言之就是此种方式最大程度的保证了执行效率,同时减少了hash碰撞概率。
.hashCode() 与 .equals()
equals()重写的同时也要重写hashCode(),目的是保证当objectA.equals(objectB)时,objectA.hashCode() 等于 objectB.hashCode() (即.hashCode()注释中的 "If two objects are equal according to the 'equals(Object)' method, then calling the 'hashCode' method on each of the two objects must produce the same integer result")
Object.hashCode() 本质上服务于 Object.equals():
举个简单的例子(只做理解,并不严谨):快递配送员要在仓库里找一个寄送到“上海市杨浦区邯郸路666号”的快件。
假如快件信息只有详细地址,则需要对每个快件地址进行查看,直到找到正确的快件;
假如快件信息包含邮编+详细地址,则只需要在邮编为XXXX的一堆快件中逐个查看就可以了,大大提升了查询效率。
求2的幂
若已知变量 x,求 >= x 的、最小的 2 的幂 y ,即:
x=8, y=8;
x=5, y=8;
x=10, y=16;
/**
* 通过移位与按位或,实现最低位到最高位 置1,然后再+1
* 详情看表格演示
*/
static byte maxYNum(byte x) {
byte n = (byte) (x - 1);
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
return n < 0 ? 1 : (n >= 64 ? 64 : (byte) (n + 1));
}
假设x=10 | |
---|---|
x = 10 | 00001010 |
n = x - 1 = 9 | 00001001 |
n >>> 1 | 00000100 |
n = n 或 n >>> 1 | 00001101 |
n >>> 2 | 00000011 |
n = n 或 n >>> 2 | 00001111 |
n >>> 4 | 00000000 |
n = n 或 n >>> 4 | 00001111 |
n + 1 = 16 | - |
即 y = 16 |
该方法为HashMap中tableSizeFor的缩略,tableSizeFor用来保证HashMap中table长度始终为2的幂。
红黑树
定义
要点
- 本质上是平衡二叉树
- 节点有红黑之分
- 红色节点必须有两个黑色子节点
- 从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点。
红黑树的优点
- 效率高 (查询、删除、插入时间复杂度O(log N))
- 插入/删除操作时少量的旋转操作,整体来说性能要优于AVL树
HashMap引入红黑树,用来提高每个bin(bucket)的操作效率