HashMap用的常有,但深入了解HashMap源码,数据结构,实现原理的人应该相对较少。今天闲暇之余,对HashMap的源码研究了一下。
HashMap在JAVA开发中,经常用到,需要使用键值对,但无需同步的,可以快速查找其中的元素,那么HashMap是怎么达到其快速定位无素的的呢?
1 首先谈一下HashMap的数据结构:
HashMap是一个由数据与链表构成的一种存储结构,水平方向是一种数组,页每个数组都是一个链表的头部。如下图:
上图中,X轴方向为HashMap的数组容器,Y轴方向,为每个相应位置的单向链表。每一个元素都是一个包含如图所示四个属性,key,value,hash,next的一种数据结构,即EntrySet,其中的next指向Y轴方向其下一个元素.
现在知道HashMap的数据结构了,那么其实现又是怎么样的?
2 HashMap的实现
首先看一下HashMap的构造函数(可能用的比较多的是,无参构造函数)
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
// Find a power of 2 >= initialCapacity
int capacity = 1;
while (capacity < initialCapacity)
capacity <<= 1;
this.loadFactor = loadFactor;
threshold = (int)(capacity * loadFactor);
table = new Entry[capacity];
init();
}
loadFactor :加载因子,加载因子与HashMap resize有关。默认为0.75
capacity:容器大小,默认值为16 其大小为上面所说的数据结构中数组的长度。
table:即为上面数据结构图中,X方向的数组(transient Entry[] table;)
threshold :resize的临界值,即当HashMap中无素个数达到该值时,HashMap就会调用其resize方法,重新扩充大小。
从下面的代码中:
while (capacity < initialCapacity)
capacity <<= 1;
可以看出,capacity的值是2的倍数,为什么?为什么?在下面我会讲到。
创建HashMap之后,我们得到了一个空的hashMap容器,我们接下来的可能就是往容器里面放我们的元素了。
public V put(K key, V value)
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;
}
当你的key为null时,会调用putForNullKey,HashMap允许key为null,这样的对像是放在table[0]中。
如果不为空,则调用int hash = hash(key.hashCode());这是hashmap的一个自定义的hash,在key.hashCode()基础上进行二次hash
static int hash(int h) {
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
这样做的目的就是为了改进传统的hash方法,而且尽量保证key的每一位都会影响到最后的hash值,以达到减少hash冲突的目的.再看indexFor方法:
hashMap是根据这个方法定位到某个元素,将要存储在X方向,即table数组的哪个位置。
static int indexFor(int h, int length) {
return h & (length-1);
}
就一行代码,将key的二次hash值,与长度减一进行与操作,这一步可谓经典,通常我们会用取模的方式来定位数组中的某个位置,但是hashMap却用这种方法,而且length即capacity的值,面capacity又是2的倍数,减1之后,表示成二进制就全部是1了,那么与全部为1的一个数进行与操作,速度会大大提升了。这就是为什么"capacity的值是2的倍数"
位定到具体的列之后,hashMap会遍历该列的所有元素,当以该key的无素已经存在是,会将其value替换,并返回其原值。否则会重新创建一个新的EntrySet并放在table[indexFor(hash, table.length)]的位置上,并将之前该列的链表,设为其next。最后是判断hashmap中元素的个数是否达到了threshold ,如果达到了则将其容器扩大到原来的2倍。如下所示:
resize(2 * table.length);
当然hashMap的get 方法,是首先通过通过key的两次hash值与数组的长度(capacity)进行于操作,定位到数组的某个位置,然后对该列的链表进行遍历,一般情况下,hashMap的这种查找速度是非常快的,hash值相同的元素过多,就会造成链表中数据很多,而链表中的数据查找是通过遍历所有链表中的元素进行的,这可能会影响到查找速度,找到即返回,这里需要注意的是,返回为null时,你不能判断是找到了,还是在hashmap中存着一个value为null的元素,因为hashmap允许value为null.
HashMap有一些比较重新的方法,比如resize,putAll,remove等,我都认真的看过。感觉代码写的非常精致。希望有兴趣的朋友也认直的去看一下。
说到HashMap不是线程完全的情况,可以用Map Collections.synchronizedMap(Map m) 或者HashTable去实现。
- 大小: 8.4 KB
- 大小: 45.9 KB
分享到:
相关推荐
《马士兵老师HashMap学习笔记详解》 HashMap是Java编程语言中常用的一种数据结构,它提供了键值对(key-value pair)的存储功能,是基于哈希表实现的。马士兵老师的HashMap学习笔记深入剖析了这一核心组件的工作...
《HashMap面试题详解》 HashMap作为Java集合框架中的重要成员,是面试中常见的知识点,尤其在数据结构与算法、并发编程以及JVM内存管理等领域,HashMap的深入理解至关重要。本篇将围绕HashMap的相关面试题,从基础...
### HashMap介绍和使用详解 #### 一、HashMap的数据结构 HashMap是Java集合框架的一个重要组成部分,它实现了Map接口,能够存储键值对映射。在Java编程语言中,最基本的数据结构有两种:数组和引用(模拟指针)。...
在Java编程语言中,集合框架是开发者日常工作中不可或缺的一部分,HashMap作为其中的重要成员,它的实现原理对于理解Java性能优化和数据结构有深远的意义。HashMap是一个基于哈希表的数据结构,它实现了Map接口,...
哈希映射(HashMap)是Java编程语言中广泛使用的数据结构之一,主要提供键值对的存储和查找功能。HashMap的实现基于哈希表的概念,它通过计算对象的哈希码来快速定位数据,从而实现了O(1)的平均时间复杂度。在深入...
HashMap之resize()方法源码解读 HashMap的resize()方法是HashMap中最核心的方法之一,该方法负责扩容HashMap的容量,以便存储更多的键值对。下面我们将对HashMap的resize()方法进行源码解读,了解其扩容机制和原理...
本套学习资料全面涵盖了HashMap的深入解析,旨在帮助求职者掌握大厂面试中的核心知识点。 HashMap是基于哈希表实现的,其底层原理主要依赖于数组和链表。它提供了O(1)的平均时间复杂度进行插入、删除和查找操作。...
Java集合专题总结:HashMap和HashTable源码学习和面试总结 本文总结了Java集合专题中的HashMap和HashTable,涵盖了它们的源码学习和面试总结。HashMap是一种基于哈希表的集合类,它的存储结构是一个数组,每个元素...
HashMap是Java编程语言中一个非常重要的数据结构,它属于集合框架的一部分,主要用于存储键值对(Key-Value)数据。HashMap在内部实现上基于哈希表,也称为散列表,它提供了一种快速查找、插入和删除数据的方法,...
"学习笔记:三数组实现的HashMap"这篇博客文章可能讨论了一种非标准但有趣的HashMap实现,使用了三个数组来代替标准的哈希表结构。这里我们将深入探讨这种三数组实现HashMap的原理和可能的优势。 1. **基本概念**:...
### HashMap与HashTable的区别详解 #### 引言 在Java编程中,`HashMap`与`HashTable`作为两种常用的数据结构,经常被用来存储键值对数据。尽管它们在功能上相似,但在实现细节、性能表现以及使用场景方面存在显著...
通过分析源码,开发者可以深入理解哈希表的工作原理,学习如何在易语言中实现高效的数据结构,这对于提升程序性能和优化内存管理至关重要。同时,这也为自定义数据结构或实现其他哈希表相关的功能提供了基础。
"Java完整随笔(学习)"可能包含了一系列关于Java编程的基础到高级概念的笔记,是学习Java的好资源。以下是一些可能涵盖的重要知识点: 1. **Java基础**:这部分可能包括了Java的基本语法,如变量、数据类型、...
Java HashMap 类详解 本资源详细介绍了 Java 中的 HashMap 类,包括其实现机制、Hash 存储机制、集合存储机制等方面的知识点。 1. HashMap 和 HashSet 的关系 HashMap 和 HashSet 是 Java Collection Framework ...
《HashMap 实例解析与关联数据结构对比》 HashMap 是 Java 中常用的一种数据结构,属于 Java.util 包下的类,它是基于哈希表实现的。在本文中,我们将深入理解 HashMap 的实例及其工作原理,并与其他数据结构如 ...
HashMap是Java编程语言中常用的集合类之一,它属于哈希表数据结构,提供key-value的存储方式,并且具有快速查询的特性。然而,HashMap本身并不保证元素的顺序,特别是当涉及到遍历或输出HashMap的内容时,顺序可能会...
HashMap 总结 HashMap 是 Java 中的一种常用的数据结构,用于存储键值对(Key-Value)数据。下面是 HashMap 的一些特性和使用方法总结。 键(Key)的特性 1. 键可以为 null:HashMap 中的键可以为 null,这意味着...
### hashMap和hashTable的区别 #### 一、简介与基本概念 `HashMap` 和 `HashTable` 都是 Java 集合框架中非常重要的数据结构,它们都实现了 `Map` 接口,用于存储键值对。尽管它们在功能上有很多相似之处,但在...
易语言HashMap类是一种在易语言编程环境中实现的高效数据结构,它主要用于存储键值对(key-value pairs),提供快速的数据存取。...通过深入学习和实践,开发者可以更好地利用HashMap类解决实际编程问题。
这是一套PPT,讲述的内容是Java的JDK中内置的几种常用的集合框架工具类的知识,重点讲解HashMap,因为不让上传视频,就先传个PPT试试;