HashMap.java的实现是面试必问的问题。

JDK版本

java version "1.8.0_91"
Java(TM) SE Runtime Environment (build 1.8.0_91-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.91-b15, mixed mode)

1. HashMap节点的封装

Node<K, V>

static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
//.....
}

hash值算法

public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
}

put null的key,计算hash值

static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

ok,重点分析一下扩容

 /**
* Initializes or doubles table size. If null, allocates in
* accord with initial capacity target held in field threshold.
* Otherwise, because we are using power-of-two expansion, the
* elements from each bin must either stay at same index, or move
* with a power of two offset in the new table.
*
* @return the table
*/
final Node<K,V>[] resize() {
Node<K,V>[] oldTab = table;
int oldCap = (oldTab == null) ? 0 : oldTab.length;
int oldThr = threshold;
int newCap, newThr = 0;
if (oldCap > 0) {
if (oldCap >= MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return oldTab;
}
else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
oldCap >= DEFAULT_INITIAL_CAPACITY)
newThr = oldThr << 1; // double threshold
}
else if (oldThr > 0) // initial capacity was placed in threshold
newCap = oldThr;
else { // zero initial threshold signifies using defaults
newCap = DEFAULT_INITIAL_CAPACITY;
newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
}
if (newThr == 0) {
float ft = (float)newCap * loadFactor;
newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
(int)ft : Integer.MAX_VALUE);
}
threshold = newThr;
@SuppressWarnings({"rawtypes","unchecked"})
Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
table = newTab;
if (oldTab != null) {
for (int j = 0; j < oldCap; ++j) {
Node<K,V> e;
if ((e = oldTab[j]) != null) {
oldTab[j] = null;
if (e.next == null)
newTab[e.hash & (newCap - 1)] = e;
else if (e instanceof TreeNode)
((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
else { // preserve order
Node<K,V> loHead = null, loTail = null;
Node<K,V> hiHead = null, hiTail = null;
Node<K,V> next;
do {
next = e.next;
if ((e.hash & oldCap) == 0) {
if (loTail == null)
loHead = e;
else
loTail.next = e;
loTail = e;
}
else {
if (hiTail == null)
hiHead = e;
else
hiTail.next = e;
hiTail = e;
}
} while ((e = next) != null);
if (loTail != null) {
loTail.next = null;
newTab[j] = loHead;
}
if (hiTail != null) {
hiTail.next = null;
newTab[j + oldCap] = hiHead;
}
}
}
}
}
return newTab;
}

首先说几点

1. 找tab位置,使用的key.hash() & (capacity - 1)

注意这里用的是位运算与操作,这里与的是capacity - 1,这样结果就不可能超过capactity - 1。不仅保证了结果正确,性能也提供了很多

2. 扩容大小为原来的大小左移一位,即扩大为原来的两倍

扩容主要的移动原来的元素,到新的数组里面

这里源码使用了比较好的方法,用key的hash值与capacity进行与,注意不是capacity - 1。如果与的结果是0,说明在新数组中的位置为原来的位置,不用变。如果结果不为0,最高为1,即capacty,说明在新数组中的位置为原来位置 + 原来的capacity

以前面试也被问道过,当时自信满满的胡说。自认为了解的很清楚,这里纠正一下

1. 封装的节点为Node,不是Entity

2. 扩容为大小为原来的两倍

3. 计算在数组位置,不是取余,是采用位操作。hashcode & capactiy - 1,注意这里的 - 1操作

4. put null的key,这里是可以的,null的hash值为0

5. key的计算为object.hashcode() ^ (object.hashcode >>> 16)

先到这

p.s.https://tech.meituan.com/java-hashmap.html这个写的不错

最新文章

  1. JAVA 中SQL字符动态拼接
  2. Xml游标
  3. JavaScript 在函数中使用Ajax获取的值作为函数的返回值
  4. hdu 1059 多重背包 背包指数分块
  5. Linux shell命令
  6. .net 并发
  7. SourceTree - 好用的 Git / Mercurial GUI 管理工具 for Mac OS X
  8. bzoj1053
  9. elasticsearch文档-analysis
  10. 获取IIS版本
  11. NOIP2014_day2:无线网络发射器选址
  12. Loj #2331. 「清华集训 2017」某位歌姬的故事
  13. kubernetes 开发 code-generator
  14. Git_GitHub-使用过程遇到的问题——坑(持续添加)
  15. 【UOJ 351】新年的叶子
  16. 每日英语:Upgrade Your Life: How to speed up your PC (or Mac)
  17. [C#]Socket通信BeginReceive异步接收数据何时回调Callback
  18. CRM rbac 组件的应用
  19. 【转载】 程序员制作996.icu网站抗议加班,你认为996能提高工作效率吗?
  20. mybatis-mysql类型映射

热门文章

  1. C# Winform下一个热插拔的MIS/MRP/ERP框架12(数据处理基类)
  2. Web 安全入门-书籍及建议
  3. error while loading shared libraies :libopencv_core_so.3.4:cannot open shared object
  4. R语言常用包汇总
  5. P4331 [BOI2004]Sequence 数字序列 (左偏树)
  6. bzoj 1005: [HNOI2008]明明的烦恼 树的prufer序列+万进制
  7. Tarjan算法打包总结(求强连通分量、割点和Tarjan-LCA)
  8. HihoCoder - 1044 状压DP 初步
  9. java 并发完成任务之CountDownLatch
  10. 解决linux一段时间不操作失去连接的问题