当你往HashMap里面put时,你其实在干什么?

 /**
* Associates the specified value with the specified key in this map.
* If the map previously contained a mapping for the key, the old
* value is replaced.
*
* @param key key with which the specified value is to be associated
* @param value value to be associated with the specified key
* @return the previous value associated with <tt>key</tt>, or
* <tt>null</tt> if there was no mapping for <tt>key</tt>.
* (A <tt>null</tt> return can also indicate that the map
* previously associated <tt>null</tt> with <tt>key</tt>.)
*/
public V put(K key, V value) {
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}
  // 如果key为空,调用putForNullKey进行处理
if (key == null)
return putForNullKey(value);
  //根据key来获得对应的hash值
int hash = hash(key);
  // 搜索指定的hash值在对应的表中的索引
int i = indexFor(hash, table.length);
  // 如果 i 索引处的 Entry 不为 null,通过循环不断遍历 e 元素的下一个元素
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
  // 当entry的hash与上面获得的key的hash相等,并且entry的key与上面的key相等(==或者equals),把value赋值给oldValue
         //这里有个问题:当 Hash 冲突严重时,在桶上形成的链表会变的越来越长,这样在查询时的效率就会越来越低;时间复杂度为 O(N)
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
} modCount++;
// 如果 i 索引处的 Entry 为 null,表明此处还没有 Entry
// 将 key、value 添加到 i 索引处,并去创建一个entry
addEntry(hash, key, value, i);
return null;
}

根据上面 put 方法的源代码可以看出,当程序试图将一个 key-value 对放入 HashMap 中时,程序首先根据该 key 的 hash() 返回值决定该 Entry 的存储位置:如果两个 Entry 的 key 的 hash() 返回值相同,那它们的存储位置相同。如果这两个 Entry 的 key 通过 equals 比较返回 true,新添加 Entry 的 value 将覆盖集合中原有 Entry 的 value,但 key 不会覆盖。如果这两个 Entry 的 key 通过 equals 比较返回 false,新添加的 Entry 将与集合中原有 Entry 形成 Entry 链,而且新添加的 Entry 位于 Entry 链的头部——具体说明继续看 addEntry() 方法的说明。

当向 HashMap 中添加 key-value 对,由其 key 的 hashCode() 返回值决定该 key-value 对(就是 Entry 对象)的存储位置。当两个 Entry 对象的 key 的 hashCode() 返回值相同时,将由 key 通过 eqauls() 比较值决定是采用覆盖行为(返回 true),还是产生 Entry 链(返回 false)。

上面程序中使用的 table 其实就是一个普通数组,每个数组都有一个固定的长度,这个数组的长度就是 HashMap 的容量。HashMap 包含如下几个构造器:

  • HashMap():构建一个初始容量为 16,负载因子为 0.75 的 HashMap。
  • HashMap(int initialCapacity):构建一个初始容量为 initialCapacity,负载因子为 0.75 的 HashMap。
  • HashMap(int initialCapacity, float loadFactor):以指定初始容量、指定的负载因子创建一个 HashMap。
 /**
* Adds a new entry with the specified key, value and hash code to
* the specified bucket. It is the responsibility of this
* method to resize the table if appropriate.
*
* Subclass overrides this to alter the behavior of put method.
*/
void addEntry(int hash, K key, V value, int bucketIndex) {
//如果key-value组成的entry数量超过极限,并且table的bucketIndex索引处不为空
if ((size >= threshold) && (null != table[bucketIndex])) {
  //把table的长度扩大到原来的两倍
resize(2 * table.length);
  //key == null的hash永远是0,如果key不为null,则会重新hash,并重新定位Entry在table中的位置
hash = (null != key) ? hash(key) : 0;
bucketIndex = indexFor(hash, table.length);
} // 获取指定 bucketIndex 索引处的 Entry
// 将新创建的 Entry 放入 bucketIndex 索引处,并让新的 Entry 指向原来的 Entry
createEntry(hash, key, value, bucketIndex);
}
 /**
* Like addEntry except that this version is used when creating entries
* as part of Map construction or "pseudo-construction" (cloning,
* deserialization). This version needn't worry about resizing the table.
*
* Subclass overrides this to alter the behavior of HashMap(Map),
* clone, and readObject.
*/
void createEntry(int hash, K key, V value, int bucketIndex) {
Entry<K,V> e = table[bucketIndex];
table[bucketIndex] = new Entry<>(hash, key, value, e);
size++;
}

JavaSE_坚持读源码_HashMap对象_put_Java1.7的更多相关文章

  1. JavaSE_坚持读源码_HashMap对象_get_Java1.7

    当你从HashMap里面get时,你其实在干什么? /** * Returns the value to which the specified key is mapped, * or {@code ...

  2. JavaSE_坚持读源码_ClassLoader对象_Java1.7

    ClassLoader java.lang public abstract class ClassLoader extends Object //类加载器的责任就是加载类,说了跟没说一样 A clas ...

  3. JavaSE_坚持读源码_Class对象_Java1.7

    Java程序在运行时,Java运行时系统一直对所有的对象进行所谓的运行时类型标识.这项信息纪录了每个对象所属的类.虚拟机通常使用运行时类型信息选准正确方法去执行,用来保存这些类型信息的类是Class类 ...

  4. JavaSE_坚持读源码_ArrayList对象_Java1.7

    底层的数组对象 /** * The array buffer into which the elements of the ArrayList are stored. * The capacity o ...

  5. JavaSE_坚持读源码_HashSet对象_Java1.7

    对于 HashSet 而言,它是基于 HashMap 实现的,HashSet 底层采用 HashMap 来保存所有元素,因此 HashSet 的实现比较简单,查看 HashSet 的源代码,可以看到如 ...

  6. JavaSE_坚持读源码_String对象_Java1.7

    /** * Compares this string to the specified object. The result is {@code * true} if and only if the ...

  7. JavaSE_坚持读源码_Object对象_Java1.7

    /** * Returns a hash code value for the object. This method is * supported for the benefit of hash t ...

  8. [一起读源码]走进C#并发队列ConcurrentQueue的内部世界

    决定从这篇文章开始,开一个读源码系列,不限制平台语言或工具,任何自己感兴趣的都会写.前几天碰到一个小问题又读了一遍ConcurrentQueue的源码,那就拿C#中比较常用的并发队列Concurren ...

  9. Java读源码之ReentrantLock(2)

    前言 本文是 ReentrantLock 源码的第二篇,第一篇主要介绍了公平锁非公平锁正常的加锁解锁流程,虽然表达能力有限不知道有没有讲清楚,本着不太监的原则,本文填补下第一篇中挖的坑. Java读源 ...

随机推荐

  1. JarvisOJ BASIC -.-字符串

    请选手观察以下密文并转换成flag形式 ..-. .-.. .- --. ..... ..--- ..--- ----- .---- ---.. -.. -.... -.... ..... ...-- ...

  2. load加载层-layui

    加载样式 //eg1 var index = layer.load(); //eg2 var index = layer.load(1); //换了种风格 //eg3 var index = laye ...

  3. CDQ题目套路总结 [未完成]

    CDQ学习资料 day1cdq分治相关 CDQ的IOI论文 1.优化斜率dp 左边对右边影响维护一个凸包解决 需要知识:①凸包②斜率dp 题目:√ HDU3842 Machine Works   HY ...

  4. 数据库 -- mysql表操作

    一,存储引擎介绍 存储引擎即表类型,mysql根据不同的表类型会有不同的处理机制 详见:https://www.cnblogs.com/peng104/p/9751738.html 二,表介绍 表相当 ...

  5. 洛谷P1123取数游戏题解

    题目 这是一道简单的搜索题,考查的还是比较基础的东西,其时搜索有时候并不难写,主要是要想到怎么搜.比如这个题,如果想二维四个方向搜则没有头绪,反之因为搜索是用递归实现的,所以我们可以使用递归的特性,把 ...

  6. GCD HDU - 1695 (欧拉 + 容斥)

    GCD Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...

  7. 【CF472G】Design Tutorial 压位

    题目大意 给出两个\(01\)序列\(A\)和\(B\) 汉明距离定义为两个长度相同的序列中,有多少个对应位置上的数字不一样 \(00111\) 和 \(10101\)的距离为\(2\) \(Q\)次 ...

  8. git errot

    常用 git 基础命令 1.错误信息 使用TortoiseGit执行pull命令时显示 git.exe pull --progress --no-rebase -v "origin" ...

  9. JeeSite 部署到linux服务器

    1.打包 改数据库连接 打包war包https://www.cnblogs.com/wdw31210/p/9878422.html 2.上传到linux 服务器的tomcat/webapps/ 下 安 ...

  10. MT【277】华中科技大学理科实验班选拔之三次方程

    (2015华中科技大学理科实验班选拔)已知三次方程$x^3+ax^2+bx+x=0$有三个实数根.(1)若三个实根为$x_1,x_2,x_3$,且$x_1\le x_2\le x_3,a,b$为常数, ...