深入理解Java HashMap

本文深入探讨了Java HashMap的原理和实现,包括HashMap的工作流程、put和get操作、hash函数、resize机制以及HashMap如何处理碰撞冲突。HashMap是非同步的,允许null键值,基于Map接口并使用哈希表实现。当元素数量超过负载因子定义的容量时,HashMap会自动resize。在Java 8中,通过红黑树优化链表过长的情况,提高查找效率。
摘要由CSDN通过智能技术生成

1. 概述

从本文你可以学习到:

  1. 什么时候会使用HashMap?他有什么特点?
  2. 你知道HashMap的工作原理吗?
  3. 你知道get和put的原理吗?equals()和hashCode()的都有什么作用?
  4. 你知道hash的实现吗?为什么要这样实现?
  5. 如果HashMap的大小超过了负载因子(load factor)定义的容量,怎么办?

当我们执行下面的操作时:

 

1

2

3

4

5

6

7

8

9

10

11

12

 

HashMap<String, Integer> map = new HashMap<String, Integer>();

map.put("语文", 1);

map.put("数学", 2);

map.put("英语", 3);

map.put("历史", 4);

map.put("政治", 5);

map.put("地理", 6);

map.put("生物", 7);

map.put("化学", 8);

for(Entry<String, Integer> entry : map.entrySet()) {

System.out.println(entry.getKey() + ": " + entry.getValue());

}

运行结果是

政治: 5
生物: 7
历史: 4
数学: 2
化学: 8
语文: 1
英语: 3
地理: 6

发生了什么呢?下面是一个大致的结构,希望我们对HashMap的结构有一个感性的认识:
hashmap

在官方文档中是这样描述HashMap的:

Hash table based implementation of the Map interface. This implementation provides all of the optional map operations, and permits null values and the null key. (The HashMap class is roughly equivalent to Hashtable, except that it is unsynchronized and permits nulls.) This class makes no guarantees as to the order of the map; in particular, it does not guarantee that the order will remain constant over time.

几个关键的信息:基于Map接口实现、允许null键/值、非同步、不保证有序(比如插入的顺序)、也不保证序不随时间变化。

2. 两个重要的参数

在HashMap中有两个很重要的参数,容量(Capacity)和负载因子(Load factor)

  • Initial capacity The capacity is the number of buckets in the hash table, The initial capacity is simply the capacity at the time the hash table is created.
  • Load factor The load factor is a measure of how full the hash table is allowed to get before its capacity is automatically increased.

简单的说,Capacity就是buckets的数目,Load factor就是buckets填满程度的最大比例。如果对迭代性能要求很高的话不要把capacity设置过大,也不要把load factor设置过小。当bucket填充的数目(即hashmap中元素的个数)大于capacity*load factor时就需要调整buckets的数目为当前的2倍。

3. put函数的实现

put函数大致的思路为:

  1. 对key的hashCode()做hash,然后再计算index;
  2. 如果没碰撞直接放到bucket里;
  3. 如果碰撞了,以链表的形式存在buckets后;
  4. 如果碰撞导致链表过长(大于等于TREEIFY_THRESHOLD),就把链表转换成红黑树;
  5. 如果节点已经存在就替换old value(保证key的唯一性)
  6. 如果bucket满了(超过load factor*current capacity),就要resize。

具体代码的实现如下:

public V put(K key, V value) {
    // 对key的hashCode()做hash
    return putVal(hash(key), key, value, false, true);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
               boolean evict) {
    Node<K,V>[] tab; Node<K,V> p; int n, i;
    // tab为空则创建
    if ((tab = table) =
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值