Java容器三:HashMap
来源:互联网 发布:什么是网络在线客服 编辑:程序博客网 时间:2024/06/05 08:40
HashMap
Map, Cloneable, Serializable
–>AbstractMap
HashMap内部是通过一个n大小的table实现的,table的每一个位置被称为一个桶,桶内可能包含很多的节点(存有key和value等值),每一个桶内的节点通过链式或树形储存。HashMap是一个fail-fast的容器。其每次扩容后的新桶数都是当前桶数的两倍(当前桶数是2的次幂)。
默认常量
// 默认HashMap容量,为2的倍数static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16// 最大容量static final int MAXIMUM_CAPACITY = 1 << 30;// 默认负载,若(元素个数/桶数)>负载,则扩容static final float DEFAULT_LOAD_FACTOR = 0.75f;/** * 1.若每一个桶内的元素个数超过TREEIFY_THRESHOLD,* 则将该桶内的链式存储结构调整为红黑树* 2.若每一个桶内的元素个数小于UNTREEIFY_THRESHOLD,* 则将该桶内的红黑树结构还原为链式结构* 注意:若桶数小于MIN_TREEIFY_CAPACITY,* 即使达到条件1,只会进行扩容而不会调整储存结构*/static final int TREEIFY_THRESHOLD = 8;static final int UNTREEIFY_THRESHOLD = 6;static final int MIN_TREEIFY_CAPACITY = 64;
HashMap的内部存储结构
链式结构
HashMap内部每一个子元素均以Node形式存储,如下所示,里面包含一个hash值,一个key值,一个value值和指向下一个Node的指针。
static class Node<K,V> implements Map.Entry<K,V> { final int hash; final K key; V value; Node<K,V> next; // 计算hash值得方法:将key的hash值和value的hash值进行异或 public final int hashCode() { return Objects.hashCode(key) ^ Objects.hashCode(value); } }
红黑树结构
static class Entry<K,V> extends HashMap.Node<K,V> { Entry<K,V> before, after;}// TreeNode最终继承至Node,该红黑树结构比普通红黑树结构稍复杂,// 因为TreeNode里还存了Node的next指针以退化为Nodestatic final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> { TreeNode<K,V> parent; // red-black tree links TreeNode<K,V> left; TreeNode<K,V> right; TreeNode<K,V> prev; // needed to unlink next upon deletion boolean red;}
成员变量
// table中的每一个元素代表一个桶transient Node<K,V>[] table;// 并未使用额外的空间进行存储,通过调用HashMap中定义的其他方法模拟出entrySet的效果transient Set<Map.Entry<K,V>> entrySet;// 已储存的元素个数transient int size;// 和其他非线程安全容器类似,为了fail-fasttransient int modCount;// 负载(默认值或赋新值)final float loadFactor;// 定义为(capacity * load factor),size超过该值即重新分配空间int threshold;
注意,在调用HashMap构造函数后并未立刻给table分配内存空间,而是在第一次进行插入操作时分配空间。
辅助方法
hash
HashMap重写的hash方法,采用将key值调用Object.hashCode方法得到的hash值的后16位与前16为进行异或,前16位保持不变得到新的hash值。
static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}
使用该方法的原因如下:
在HashMap中通过hash值计算得到内存的方法为index=hash&(n-1)
,n为table大小,即桶的数量,且n值为2的幂次,因此该方法会造成在计算Index时仅后
引自博客http://blog.csdn.net/fan2012huan/article/details/51097331
tableSizeFor
该方法的主要作用是将输入的桶的数量(cap)变成大于cap的最小2次幂的数。
static final int tableSizeFor(int cap) { // 当cap为2的次幂时,保证使用该方法不改变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;}
该方法的原理如下:
以cap为1**************为例,*代表该位置上的数是任意数
n |= n >>> 1;
1************** -> 11*************,将最高位的1向右传递了2位。
n |= n >>> 2;
1************** -> 1111***********,将最高位的1向右传递了4位。
n |= n >>> 4;
1111*********** -> 11111111*******,将最高位的1向右传递了8位。
n |= n >>> 8;
11111111******* -> 111111111111111,将最高位的1向右传递了16位(位数不够,仅传递了15位)。
n |= n >>> 16;
最大能将最高位的1向右传递32位,和一个int值得位数相同。
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
最后返回(n+1),即为2的次幂。
查找元素的实现
该方法在HashMap的内部频繁被其他方法调用。该方法的实现原理其实就是根据hash值定位到桶,再从桶中查找到期望的Node。注意,即使在桶内,每一个if的最开始都判断了一次hash值是否相同,这是因为桶的标号是通过index=hash&(n-1)
计算得到,在之前解释过,这样在计算index时只会用到后n为hash值,因此有可能不同的hash值都定位到同一个桶中。
final Node<K,V> getNode(int hash, Object key) { Node<K,V>[] tab; Node<K,V> first, e; int n; K k; if ((tab = table) != null && (n = tab.length) > 0 && (first = tab[(n - 1) & hash]) != null) { if (first.hash == hash && // always check first node ((k = first.key) == key || (key != null && key.equals(k)))) return first; if ((e = first.next) != null) { if (first instanceof TreeNode) return ((TreeNode<K,V>)first).getTreeNode(hash, key); do { if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) return e; } while ((e = e.next) != null); } } return null;}
- Java容器三:HashMap
- Java容器 HashMap
- Java容器之HashMap
- java容器----HashMap
- java容器类---HashMap、HashSet
- java容器类---HashMap、HashSet
- Java容器----HashMap vs HashTable
- Java容器-HashMap和HashTable
- Java容器HashMap源代码解析
- Java容器类浅析三-----保证插入顺序的HashMap--LinkedHashMap的存取原理
- Java(三)--容器
- Java 容器(三) Set
- java容器--Map{Hashtable,HashMap,WeakHashMap}
- Java容器类List、ArrayList、HashTable、HashMap
- Java容器中HashMap的基本用法
- Java容器 HashMap与HashSet的学习
- Java容器:HashMap和HashSet解析
- java容器源码--hashmap源码解读
- Java (while结构)
- Spring02
- 初学DP
- web框架学习前复习——xml(1)
- Face Detection with the Faster R-CNN(数据集标注对比研究报告 )
- Java容器三:HashMap
- RoboCup中使用Gazebo和ROS
- android 压缩和解压文件
- 【codevs 3538】奇怪的函数
- Shiro——shiro架构
- IOS Dev Intro - IOS Interview QAs
- 要能真正提升产品开发团队的效率与质量, 你必需要懂得如何 ”设计” 开发团队所需要的实践或框架
- php sha1 hmac
- 二维数组中的查找