HashMap存储分析
来源:互联网 发布:上网记录监控软件 编辑:程序博客网 时间:2024/05/24 05:50
通过代码 transient Entry[] table;可以看出有一个Entry数组。
static class Entry<K,V> implements Map.Entry<K,V> {
final K key;
V value;
Entry<K,V> next;
final int hash;
}
通过上面这段代码可以看出:
内部类Entry中有四个属性信息,分别为key,value,next指针,hash值,即每一个Entry对象都有这四个信息。
通过for (Entry<K,V> e = table[i]; e != null; e = e.next ) 这个for循环代码可以看出:
table数组中,每一个位置都存有一些Entry对象信息,而这些信息用next连接了起来,就形成了一个链表,所以table数组中的每一个位置都存有Entry对象的链表(当然了,也可能是null)。
再看一下put代码:
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
//计算用自己的hash方法计算hash值
int hash = hash(key.hashCode());
//用计算出的hash值与table的长度进行与运算,计算出要put的键值对存放的table数组的位置i
int i = indexFor(hash, table .length );
//循环遍历table数组位置i下的链表信息
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
//如果要存储的key的hash值与table数组位置i下的某个链表节点的hash值相等,
//并且,key值也相等,那么就执行替换操作
if (e. hash == hash && ((k = e. key) == key || key.equals(k))) {
V oldValue = e. value;
e. value = value;
e.recordAccess( this);
return oldValue;
}
}
modCount++;
//如果循环遍历之后,没有找到hash和key都相同的Entry节点,那么就在table数组的位置i处,
//插入一个Entry节点信息,addEntry方法中有四个参数,分别是hash值,key,value,table数组的位置i
addEntry(hash, key, value, i);
return null;
}
再看一下addEntry方法:
void addEntry(int hash, K key, V value, int bucketIndex) {
//在插入之前,首先将table数组的位置i处的所有Entry节点信息都保存到e对象中,因为table数组的每一个位置都是一个Entry对象。
//在插入之前,首先将table数组的位置i处的所有Entry节点信息都保存到e对象中,因为table数组的每一个位置都是一个Entry对象。
Entry<K,V> e = table[bucketIndex];
//然后新建一个Entry对象,然后将这个新建的Entry对象再赋值给table数组的位置i处。
table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
if (size++ >= threshold)
resize(2 * table. length);
}
单独拿出new Entry<K,V>(hash, key, value, e);来说一说:
新建一个Entry对象,传入的参数有四个,分别是根据key计算出来的hash,key,value,以及table数组的位置i处的所有Entry节点信息。
看一下Entry的构造方法
Entry( int h, K k, V v, Entry<K,V> n) {
value = v;
next = n;
key = k;
hash = h;
}
根据 next = n;可以知道,我新建一个Entry对象节点,然后将next指针指向了传入的参数n(即上面保存table[bucketIndex]的e对象节点),我觉得新建的这个Entry对象节点应该会指向原来的Entry对象的头节点处。 此时table[i]的位置的那个Entry对象应该改变了,变成刚刚新创建的那个Entry对象节点了。当再次put的时候,再次执行这个for循环的时候for (Entry<K,V> e = table[i]; e != null ; e = e.next ) 只是table[i]的值变化了一下,table[i]处的Entry链表长度变化了一下。
分析完put方法之后,再分析一下get方法:
public V get(Object key) {
if (key == null)
return getForNullKey();
//计算key值的hash值,与put方法的一样
int hash = hash(key.hashCode());
//用indexFor(hash, table. length)方法进行与运算,然后找到了要在table数组取值的位置
//循环遍历table[i]处的Entry链表节点
for (Entry<K,V> e = table[ indexFor(hash, table. length)];
e != null;
e = e. next) {
Object k;
//如果key值的hash与table数组中存储的Entry对象e的hash值相等,同时key值相等,那么,就说明找到了,并返回value值。
if (e. hash == hash && ((k = e. key) == key || key.equals(k)))
return e. value;
}
return null;
}
- HashMap存储分析
- HashMap和HashSet(深入HashMap源码分析HashMap元素的存储)
- HashMap和HashSet(深入HashMap源码分析HashMap元素的存储)
- 通过 HashMap、HashSet 的源代码分析其 Hash 存储机制
- 通过 HashMap、HashSet 的源代码分析其 Hash 存储机制
- JDK源码学习之HashMap (一) : 底层存储结构分析
- HashMap 分析
- HashMap分析
- HashMap分析
- HashMap分析
- HashMap分析
- HashMap分析
- HashMap分析
- HashMap分析
- hashMap 分析
- HashMap分析
- HashMap分析
- hashmap 分析
- Hibernate 的 select语句
- 简记2013 ACM/ICPC Asia Regional Changsha Online
- 【百度地图API】如何将Google的经纬度批量转换为百度经纬度
- 安装SDK2003并且编译Ghost
- 九度OJ 9月赛第二场 题目1542:黑白迷阵 (状态压缩DP)
- HashMap存储分析
- STM32仿真停在0x08001460 BEAB BKPT 0xAB这个_sys_open代码下
- DML误操作基于时间点的不完全恢复
- 二值化方法总结——附录程序
- android WIFI学习总结
- leetcode_question_116 Populating Next Right Pointers in Each Node
- DDL误操作基于scn的不完全恢复
- 线性表的-顺序表
- 弹出层