static class Entry<K,V> implements Map.Entry<K,V> { final K key; V value; Entry<K,V> next; ... }
既然是个数组,那么数组是要声明容量的,这个工作在初始化HashMap的时候完成 ,我们看默认的初始化方法
public HashMap() { this.loadFactor = DEFAULT_LOAD_FACTOR; threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR); table = new Entry[DEFAULT_INITIAL_CAPACITY]; init(); }
这里的容量定义为DEFAULT_INITAL_CAPACITY ,是个常量,默认值是16。也就是说你声明一个HashMap,默认给你的是16个桶来放Key(注意是key ,不是value,所以并不意味着初始的HashMap只能容纳16组Entry),当key超过16时就得扩容了。具体扩容方法,是超过threshhold后就会触发resize()重新hash。因此初始化HashMap时根据数据情况合理的设置容量是必要得。
void resize(int newCapacity) { Entry[] oldTable = table; int oldCapacity = oldTable.length; if (oldCapacity == MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return; } Entry[] newTable = new Entry[newCapacity]; transfer(newTable); table = newTable; threshold = (int)(newCapacity * loadFactor); }
二、存取算法
具体来说就是常用的put(),get()方法的源码
public V put(K key, V value) { if (key == null) return putForNullKey(value); int hash = hash(key.hashCode()); int i = indexFor(hash, table.length); for (Entry<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; }
put一个值的时候首先会根据key的hashCode()方法计算hash值,然后会根据这个hash值计算entry数组(桶)的下标(i)在具体判断是否key 命中时,是根据 e.hash==hash&& ((k = e.key) == key || key.equals(k))) 这个表达式。从而我们知道,HashMap判断当前是否已经存储了一个值是根据key的hashCode() 和equal() 来判断的。所以如果要用自定义对象来作key,需要重写这两个方法,保证相同对象的一致性。
那么如果上面执行下来没有发现相同的key,这里有两种情况,一是没有桶,也就是entry数组没有位置。二是有桶(Hash命中)但是链表中找不到,这两种情况都可以通过addEntry(hash, key, value, i)这个方法把新值put进去。
void addEntry(int hash, K key, V value, int bucketIndex) { Entry<K,V> e = table[bucketIndex]; table[bucketIndex] = new Entry<K,V>(hash, key, value, e); if (size++ >= threshold) resize(2 * table.length); }
这个方法很短,但是完成了很多工作,一是new了一个entry, 二是监视当前的桶大小是否超过阈值,如果超过就进行扩容。这个地方其实容易迷糊,看起来似乎是new了一个Entry对象把老对象替换掉了。此时请记得,entry是一个链表,new的过程可能是新创建一个链表,也可能是在已有链表上添加一个节点。
put搞明白了,get就很容易理解了。
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; }
其实完成的就是put前半段查找的过程。如果找不到,会返回null。
通过上面分析,HashMap是怎么存储与运作的应该知道个大概了。总体来说,我想有两个地方比较关键,一是对与容量(Capacity )的规划,二是hashCode()的实现。应用的得当应该会让HashMap效率提高不少档次。另外有一点,看源码就发现HashMap的方法都没有做synchronize,相比而言Hashtable实现原理基本类似,但是其存取方法都是synchronized, 因此hashMap非线程安全,但是相应的效率会比较高。
相关推荐
Java HashMap原理分析 Java HashMap是一种基于哈希表的数据结构,它的存储原理是通过将Key-Value对存储在一个数组中,每个数组元素是一个链表,链表中的每个元素是一个Entry对象,Entry对象包含了Key、Value和指向...
HashMap是Java编程语言中最常用的集合类之一,它属于`java.util`包,提供了一种以键值对形式存储数据的数据结构。HashMap的核心在于其高效的数据查找、...阅读“HashMap原理.pdf”文件,可以获得更深入的细节和示例。
### HashMap原理详解 #### 一、HashMap简介与应用场景 HashMap是Java集合框架中一个非常重要的组成部分,它提供了基于键值对(key-value)映射的高效数据存储方式。由于其内部采用了数组加链表(以及红黑树优化)的...
一线大厂BATJ面试题讲解-hashmap原理实现
在深入探讨HashMap的实现原理之前,我们需要了解两个关键的接口方法:`hashCode()`和`equals()`。 根据《Effective JAVA》的建议,当重写`equals()`方法时,也应重写`hashCode()`方法。这是因为在HashMap中,`...
HashMap原理的深入理解 HashMap是基于哈希表的Map接口的非同步实现,提供了所有可选的映射操作,并允许使用null值和null键。HashMap储存的是键值对,HashMap很快。此类不保证映射的顺序,特别是它不保证该顺序恒久...
要理解HashMap的工作原理,首先需要了解它如何结合数组和链表的特点来提升性能。数组的特点是查找速度快,因为它们在内存中是连续分布的,这使得通过下标访问特定元素的时间复杂度是O(1)。但数组的缺点在于其大小是...
hashMap基本工作原理,图解分析,基础Map集合
详细介绍了hashMap原理,值得一看,对于面试者有很大帮助
Java HashMap原理及实例解析 Java HashMap是一种常用的数据结构,它提供了快速的查找、插入、删除操作。HashMap的键值对的存储方式是通过键值对来存储数据的,键是唯一的,不可以重复的,而值可以重复。 HashMap的...
本教程特点: 1.更适合零基础学员: ·自Java语言起源始,循序渐进,知识点剖析细致且每章配备大量随堂练习,让你步步为营,学得透彻、练得明白 ·拒绝晦涩难懂的呆板教学,宋老师语言生动幽默,举例形象生动深入浅...
HashMap底层原理.md
### CAS操作原理 CAS操作包含三个参数:内存地址V、预期值A和新值B。如果内存地址V的值等于预期值A,则将V的值更新为新值B,整个过程是原子性的。如果V的值不是A,则操作失败,不会进行任何修改。Java中的`...
文章目录一.HashMap是什么二.HashMap继承类对比分析三.HashMap源码相关单词含义四.HashMap如何确定哈希桶数组索引位置五. HashMap 的 put 方法分析六.HashMap扩容机制七.HashMap线程安全性 一.HashMap是什么 ...
HashMap的底层原理主要依赖于哈希表,这是一种数据结构,它通过计算键的哈希码来实现高效的查找操作。 在HashMap中,每个元素都是一个键值对,存储在一个Entry对象中。当向HashMap添加键值对时,首先会计算键的哈希...
对HashMap 源码逐行进行注释,带你深入理解HashMap原理,使面试不在困难,
hashMap基本工作原理,图解分析,基础Map集合
HashMap是Java中非常常见的一种数据结构,主要用于存储键值对,其核心原理是通过哈希算法将键映射到数组中的位置来实现快速访问。本文将详细介绍HashMap的底层原理,包括其内部实现结构、关键字段的作用、以及JDK ...
在Java编程语言中,集合框架是开发者日常工作中不可或缺的一部分,HashMap作为其中的重要成员,它的实现原理对于理解Java性能优化和数据结构有深远的意义。HashMap是一个基于哈希表的数据结构,它实现了Map接口,...