HashMap源码--(三)put方法
来源:互联网 发布:sql日月年转年月日 编辑:程序博客网 时间:2024/06/05 02:17
HashMap源码–(三)put方法
Map内部的数据结构是以key-value键值对的方式存数据。key和value都可以为空。
Map有很多子类,HashMap、LinkedListMap、TreeMap等, HashMap是比较常用的,它的存取速度快,是基于哈希表的Map接口实现。存取数据时是根据哈希算法计算数据存在位置,在相同哈希值计算的位置存放的数据结构是链表。添加元素使用方法put方法,如下。
/** * 将指定的value和指定的key映射到map中。 * 如果map中包含这个key,则替换。 * * @param key 一个对象,例如字符,用于映射指定的值 * @param value map中存的值,根据映射的key进行获取的值 * @return 如果map中存在key,则返回被替换的值;如果key不存在 * 则返回null。根据返回值key判断map中是否存在。 */ public V put(K key, V value) { //key为null时,添加或替换value if (key == null) return putForNullKey(value); //获取哈希值 int hash = hash(key.hashCode()); //根据哈希值和Entry[] table数组的长度计算出value存放的位置 int i = indexFor(hash, table.length); //根据数组的位置找到链表的表头 for (Entry<K,V> e = table[i]; e != null; e = e.next) { //根据哈希值和key查找Entry Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; //当值被覆盖时触发的方法,暂时是空方法 e.recordAccess(this); return oldValue; } } //操作次数加1 modCount++; //Entry数组为找到key,添加数据 addEntry(hash, key, value, i); return null; }
put方法添加或修改数据时,key为null时的添加方法为:
/** * key为null时添加值 */ private V putForNullKey(V value) { for (Entry<K,V> e = table[0]; e != null; e = e.next) { if (e.key == null) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(0, null, value, 0); return null; }
key的值决定了值存放在Entry数组的位置,key为null时,存放在Entry数组下标为0的位置;key不为null时,要根据哈希算法和数组的长度计算存放位置,存放位置算法如下:
/** *计算hash值 */ static int hash(int h) { h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); } /** * 根据数组的长度,计算哈希值h在数组的位置 */ static int indexFor(int h, int length) { return h & (length-1); }
相同的key用hash(int h)方法计算出相同的值。hash方法采用位移算法,这个算法采用高位计算,防止低位不变,高位变化时,hash值冲突问题。
indexFor方法是计算hash值h在数组存放的位置。该方法运用的很巧妙,当length的长度为2的幂指数时,h & (length-1)计算公式相当于对length取模,但&的效率比%高。
假设数组长度分别为15和16,优化后的hash码分别为8和9,那么&运算后的结果如下:
h & (table.length-1) hash table.length-1 8 & (15-1): 0100 & 1110 = 0100 9 & (15-1): 0101 & 1110 = 0100 --------------------------------------------------- 8 & (16-1): 0100 & 1111 = 010 9 & (16-1): 0101 & 1111 = 0101
可以看出当长度为15时,8和9对应的值是相同的,长度为16时,值则不相同。可见HashMap的长度为2的幂指数的巧妙,且根据长度获取位置也很高效。
根据数组位置i获取Entry对象, for (Entry<K,V> e = table[i]; e != null; e = e.next)
这个对象Entry e是链表的表头,它的next指向链表的下一个对象。 if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
在链表中匹配hash值和key,进行覆盖。
- HashMap源码--(三)put方法
- HashMap源码注解 之 put()方法(六)
- HashMap源码解析——put方法
- HashMap之put方法源码解析
- HashMap的put()方法
- HashMap.put/get方法
- Java 1.8 HashMap 源码中 put()方法详解
- 【源码分析】HashMap的put(K k,V v)方法
- HashMap的put源码解析
- HashMap源码分析(四)put-jdk8-红黑树的引入
- jdk1.8 HashMap源码分析(put函数)
- HashMap学习笔记:put方法
- HashMap源码解析(三)
- java hashmap的put函数实现源码
- JDK1.8 HashMap中put源码分析
- hashMap--put(k,v)源码分析
- JDK源码之解读hashMap 的put和get方法的实现原理
- java 8 Hashmap深入解析 —— put get 方法源码
- 项目中遇到的问题总结
- 20170925_HTTP协议的五种状态
- Android PopupWindow用法(一)
- 如何生成背景颜色带渐变效果的按钮
- RGB颜色查询表
- HashMap源码--(三)put方法
- Android 小米手机开发APP图标更换后还显示原来的图标
- 优化或修改CentOS最大连接数限制
- CIR,CBS,EBS,PIR,PBS令牌桶概述
- Android RuntimePermissions运行时权限:批量权限申请
- 189. Rotate Array
- quartz 定时任务管理
- Hive
- poj1000-1009小结