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这个写的不错

HashMap put、get方法源码分析的更多相关文章

  1. hashmap的put方法源码分析

    put主源码如下: public V put(K key, V value) { if (key == null) return putForNullKey(value); int hash = ha ...

  2. 【转】HashMap实现原理及源码分析

    哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景极其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表,而HashMap的实现原理也常常出 ...

  3. HashMap实现原理及源码分析之JDK8

    继续上回HashMap的学习 HashMap实现原理及源码分析之JDK7 转载 Java8源码-HashMap  基于JDK8的HashMap源码解析  [jdk1.8]HashMap源码分析 一.H ...

  4. java-通过 HashMap、HashSet 的源码分析其 Hash 存储机制

    通过 HashMap.HashSet 的源码分析其 Hash 存储机制 集合和引用 就像引用类型的数组一样,当我们把 Java 对象放入数组之时,并非真正的把 Java 对象放入数组中.仅仅是把对象的 ...

  5. 每天学会一点点(HashMap实现原理及源码分析)

    HashMap实现原理及源码分析   哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希 ...

  6. Java split方法源码分析

    Java split方法源码分析 public String[] split(CharSequence input [, int limit]) { int index = 0; // 指针 bool ...

  7. invalidate和requestLayout方法源码分析

    invalidate方法源码分析 在之前分析View的绘制流程中,最后都有调用一个叫invalidate的方法,这个方法是啥玩意?我们来看一下View类中invalidate系列方法的源码(ViewG ...

  8. Linq分组操作之GroupBy,GroupJoin扩展方法源码分析

    Linq分组操作之GroupBy,GroupJoin扩展方法源码分析 一. GroupBy 解释: 根据指定的键选择器函数对序列中的元素进行分组,并且从每个组及其键中创建结果值. 查询表达式: var ...

  9. HashMap实现原理及源码分析

    哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表,而HashMap的实现原理也常常出 ...

  10. HashMap实现原理及源码分析(JDK1.7)

    转载:https://www.cnblogs.com/chengxiao/p/6059914.html 哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技 ...

随机推荐

  1. IO相关3(string流)

    sstream 头文件定义了三个类型来支持内存 IO,这些类型可以向 string 写入数据,从 string 读取数据,就像 string 是一个 IO 流一样. istringstream 从 s ...

  2. 洛谷P3122 [USACO15FEB]圈住牛Fencing the Herd(计算几何+CDQ分治)

    题面 传送门 题解 题目转化一下就是所有点都在直线\(Ax+By-C=0\)的同一侧,也就可以看做所有点代入\(Ax+By-C\)之后的值符号相同,我们只要维护每一个点代入直线之后的最大值和最小值,看 ...

  3. LVS解决高并发,大数据量

    http://www.360doc.com/content/14/0726/00/11962419_397102114.shtml LVS的全称Linux vitual system,是由目前阿里巴巴 ...

  4. 关于fatal error LINK1123:failure during conversion to COFF:file invalid or corrupt

    今天用Visual Studio 2010编译postgresql工程时突然遇到下面这个编译错误: fatal error LINK1123:failure during conversion to ...

  5. 使用@符号让C#中的保留字做变量名的方法详解

    原来还有一种办法就是加@符号(看了@符号的作用又多了一个): 复制代码代码如下: class @int    {        static void Main(string[] args)      ...

  6. SDUT OJ 效率至上(线段树)

    效率至上 Time Limit: 5000 ms Memory Limit: 65536 KiB Submit Statistic Problem Description 题意很简单,给出一个数目为n ...

  7. shared_ptr智能指针

    来自博客:https://www.cnblogs.com/lzpong/p/6188034.html 多线程程序经常会遇到在某个线程A创建了一个对象,这个对象需要在线程B使用, 在没有shared_p ...

  8. JavaWeb学习笔记(七)—— JSP

    一.什么是JSP JSP全名是Java Server Pages,它是建立在Servlet规范之上的动态网页开发技术.在JSP文件中,HTML代码与Java代码共同存在,其中,HTML代码用来实现网页 ...

  9. 校园网络安全CTF 第一题 和 你真了解我吗?

    第一题: 需要先找到相应头(REsponse header中的tips) <?php$flag = "***";if (isset($_GET['repo']))//检测变量 ...

  10. Kibana6.x.x源码分析--JavaScript中 "!~" 这样的符号是啥意思?

    看到源码中有一段JS代码不太懂,如下: 里面这个 "!~" 符号看到后有点儿方啊O__O "…,毛线意思? [查资料,解释如下]: indexOf returns -1 ...