HashMap中put和get方法的底层详解

注意:Key和Value存储的不是值,而是对象地址,这个地址指向我们给他赋的值(涉及到自动装箱)!!!!

通过map.put(Key, Value)添加元素的底层实现:

第一步 :将Key, Value封装到Node对象中。
第二步:底层调用k的HashCode()方法返回Hash值,通过哈希算法得到一个数组的下标,如果数组的该位置处没有任何元素,那么就将该Node添加到数组的该位置,如果有元素,那么拿着该Node的Key和该数组位置的节点的Key进行equals()如果都为false,该节点被添加在链表的末尾,如果链表的某节点处为true,则利用该Node的Value值去覆盖当前的节点处的Value值。

map.get(key)方法的底层实现:

先调用Key的Hashcode方法得到哈希值,通过哈希算法得到对应的数组的下标,通过数组下标快速定位到某个位置上,如果这个位置上什么也没有,则返回null,如果这个位置上有单向链表,那么会拿着参数k和单项链表中的每个节点的k进行比较(equals()),如果所有的节点都返回false,那么最终该方法返回null,如果有一个节点的k和我们的k相匹配,那么该k节点所对应的value就是我们要找的value。

总结:拉链法处理冲突

hashMap集合Key部分特点:

在存储元素时需要重写Hashcode和equals方法。
无序不可重复。
放在hashMap集合的Key部分的元素实际上就是放到HashSet中了,所以hashSet中的hashcode和equals方法都需要重写。
放在HashMap的Key部分的元素和放在HashSet中的元素需要同时重写hashcode和equals()方法。

hashMap存储元素的特点:

HashMap初始化容量时16,默认加载因子为0.75,既当数组的容量占所有的容量的75%时,自动扩容,且HashMap初始化容量最好为2的倍数(官方推荐),才能达到冲突的几率最小。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
HashMapJava最常用的哈希表实现之一,它基于哈希表实现了Map接口。以下是HashMap源码的详细解释: HashMap内部是由一个数组和链表组成的,数组的每个元素称为桶,每个桶存储一个链表(可能为空),链表的每个节点都是一个键值对(key-value pair)。 以下是HashMap的主要属性: ```java transient Node<K,V>[] table; // 存储元素的数组 transient int size; // 元素大小 int threshold; // 扩容阈值 final float loadFactor; // 负载因子 ``` 其,table是一个transient修饰的Node数组,存储HashMap的元素;size表示HashMap元素的个数;threshold表示HashMap的扩容阈值,即当元素个数达到这个值时就需要扩容;loadFactor是负载因子,用于决定HashMap何时需要扩容。 以下是HashMap的主要方法: 1. put(K key, V value) :将指定的键值对添加到HashMap,如果键已经存在,则更新对应的值。 2. get(Object key):获取指定键对应的值,如果键不存在则返回null。 3. remove(Object key):从HashMap删除指定的键值对,如果键不存在则返回null。 4. clear():从HashMap删除所有的键值对。 5. resize():扩容HashMap,将table的大小增加一倍。 6. hash(Object key):计算键的哈希值。 7. getNode(int hash, Object key):获取指定键的节点。 8. putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict):实际执行put操作的方法,会根据指定的参数决定是否更新已有键的值、是否删除过期键等。 HashMap的put方法实现如下: ```java public V put(K key, V value) { // 计算键的哈希值 int hash = hash(key); // 计算键在table数组的索引 int i = indexFor(hash, table.length); // 遍历桶链表,查找指定键 for (Node<K,V> e = table[i]; e != null; e = e.next) { 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; } } // 如果指定键不存在,则创建新的节点,并将其添加到桶的链表 modCount++; addEntry(hash, key, value, i); return null; } ``` 在这个方法,我们首先计算键的哈希值,然后计算键在table数组的索引。接着,我们遍历桶链表,查找指定键,如果键已经存在,则更新对应的值。否则,我们创建新的节点,并将其添加到桶的链表HashMap的get方法实现如下: ```java public V get(Object key) { // 计算键的哈希值 int hash = hash(key); // 计算键在table数组的索引 int i = indexFor(hash, table.length); // 遍历桶链表,查找指定键 for (Node<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { // 如果找到指定键,则返回其对应的值 return e.value; } } // 如果指定键不存在,则返回null return null; } ``` 在这个方法,我们首先计算键的哈希值,然后计算键在table数组的索引。接着,我们遍历桶链表,查找指定键,如果找到指定键,则返回其对应的值。 HashMap的remove方法实现如下: ```java public V remove(Object key) { // 计算键的哈希值 int hash = hash(key); // 计算键在table数组的索引 int i = indexFor(hash, table.length); // 遍历桶链表,查找指定键 Node<K,V> prev = table[i]; Node<K,V> e = prev; while (e != null) { Node<K,V> next = e.next; Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { modCount++; size--; if (prev == e) { table[i] = next; } else { prev.next = next; } e.recordRemoval(this); return e.value; } prev = e; e = next; } // 如果指定键不存在,则返回null return null; } ``` 在这个方法,我们首先计算键的哈希值,然后计算键在table数组的索引。接着,我们遍历桶链表,查找指定键,如果找到指定键,则从链表删除节点,并返回其对应的值。否则,我们返回null。 以上就是HashMap源码的详细解释。HashMap是一个非常常用且实用的数据结构,它的实现原理也非常值得深入学习和理解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值