HashMap深度解析
来源:互联网 发布:java反射得到字段的值 编辑:程序博客网 时间:2024/06/08 00:18
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"></span><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">hashmap是一种以键值对存储的数据容器,根据key的hashcode值决定存储位置</span>
1、内部存储对象是Entry<Key,Value>;
2、内部的每个对象都会生产一个hashcode值,在存储Entry<Key,Value>时根据Key的hashcode以一定的映射关系存储;
3、获取数据时,根据Key的hashcode和对应的映射关系,直接定位数据的位置。
HashMap内部维护的是数组+链表的结构来存储Entry<Key,Value>。数组的形式是Entry[] table数组,初始化HashMap的时候数组的长度默认为16,Entry[] table 数组的每个元素要么为null要么是由Entry<Key,Value>组成的链表。HashMap中的Entry<Key,Value>的个数为HashMap的大小(size)。
下面介绍几个概念:
阀值(threshold)=容量(capacity)*加载因子(load factor)
容量(capacity):是指HashMap内部Entry[] table线性数组的长度
加载因子(load factor):默认为0.75
阀值(threshold):当HashMap大小超过了阀值,HashMap将扩充2倍,并且rehash。
两个重要的方法:put/get
put()方法-向HashMap存储键值对<Key,Value>
a. 获取这个Key的hashcode值,根据此值确定应该将这一对键值对存放在哪一个桶中,即确定要存放桶的索引;
b. 遍历所在桶中的Entry<Key,Value>链表,查找其中是否已经有了以Key值为Key存储的Entry<Key,Value>对象,
c1. 若已存在,定位到对应的Entry<Key,Value>,其中的Value值更新为新的Value值;返回旧值;
c2. 若不存在,则根据键值对<Key,Value> 创建一个新的Entry<Key,Value>对象,然后添加到这个桶的Entry<Key,Value>链表的头部。
d. 当前的HashMap的大小(即Entry<key,Value>节点的数目)是否超过了阀值,若超过了阀值(threshold),则增大HashMap的容量(即Entry[] table 的大小),并且重新组织内部各个Entry<Key,Value>排列。
/** * 将<Key,Value>键值对存到HashMap中,如果Key在HashMap中已经存在,那么最终返回被替换掉的Value值。 * Key 和Value允许为空 */ public V put(K key, V value) { //1.如果key为null,那么将此value放置到table[0],即第一个桶中 if (key == null) return putForNullKey(value); //2.重新计算hashcode值, int hash = hash(key.hashCode()); //3.计算当前hashcode值应当被分配到哪一个桶中,获取桶的索引 int i = indexFor(hash, table.length); //4.循环遍历该桶中的Entry列表 for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; //5. 查找Entry<Key,Value>链表中是否已经有了以Key值为Key存储的Entry<Key,Value>对象, //已经存在,则将Value值覆盖到对应的Entry<Key,Value>对象节点上 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {//请读者注意这个判定条件,非常重要!!! V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; //6不存在,则根据键值对<Key,Value> 创建一个新的Entry<Key,Value>对象,然后添加到这个桶的Entry<Key,Value>链表的头部。 addEntry(hash, key, value, i); return null; } /** * Key 为null,则将Entry<null,Value>放置到第一桶table[0]中 */ 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; }get方法:
a. 获取这个Key的hashcode值,根据此hashcode值决定应该从哪一个桶中查找;
b. 遍历所在桶中的Entry<Key,Value>链表,查找其中是否已经有了以Key值为Key存储的Entry<Key,Value>对象;
c1. 若已存在,定位到对应的Entry<Key,Value>,返回value;
c2. 若不存在,返回null
** * Returns the value to which the specified key is mapped, * or {@code null} if this map contains no mapping for the key. * 返回key对应的Value值,如果HashMap中没有,则返回null; * 支持Key为null情况 * <p>More formally, if this map contains a mapping from a key * {@code k} to a value {@code v} such that {@code (key==null ? k==null : * key.equals(k))}, then this method returns {@code v}; otherwise * it returns {@code null}. (There can be at most one such mapping.) * * <p>A return value of {@code null} does not <i>necessarily</i> * indicate that the map contains no mapping for the key; it's also * possible that the map explicitly maps the key to {@code null}. * The {@link #containsKey containsKey} operation may be used to * distinguish these two cases. * * @see #put(Object, Object) */ public V get(Object key) { if (key == null) return getForNullKey(); int hash = hash(key.hashCode()); //遍历列表 for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) return e.value; } return null; }Hashmap中删除节点:
1. 根据Key的hashcode 值和Key定位到Entry<key,Value> 对象在HashMap中的位置;
2. 由于Entry<Key,Value>是一个链表元素,之后便是链表删除节点的操作了;
- HashMap深度解析(一)
- HashMap深度解析(二)
- HashMap深度解析
- HashMap深度解析(二)
- HashMap深度解析(一)
- HashMap深度解析(一)
- HashMap深度解析(二)
- HashMap深度解析(一)
- HashMap深度解析(二)
- HashMap深度解析(一)
- HashMap深度解析(二)
- HashMap深度解析(一)
- HashMap深度解析(一)
- HashMap深度解析(一)
- HashMap深度解析(二)
- HashMap深度解析(一)
- HashMap深度解析(二)
- HashMap深度解析(一)
- 同步(1)
- 内核抢占与中断返回
- struts2核心工作流程与原理
- ViewPager翻页特效
- vue.js视频教程,vue.js视频教程下载
- HashMap深度解析
- [2016-09-14]Ubuntu Django+Apache2+Mod_wsgi 配置
- 批量修改文件名
- C++ 详解几种类型转换
- UGUI内核大探究(四)Selectable与Button
- [电影]《指环王》新老三部曲完全赏析(序)
- Spiral Matrix II
- 马克飞象
- linux上 rlwrap安装