[size=small]Java集合中,HashMap的点名率很高,这归功于它的Key-Value键值对结构,还有它不错的效率。HashMap由于运用Hash算法定位并配合它的存储方式使它有了不错的效率,理解
它的存储方式对我们自己日常开发也有启发作用,就让我们一同来学一些吧~[/size]
[size=small]首先看它的构造方法
HashMap()
构造一个具有默认初始容量 (16) 和默认加载因子 (0.75) 的空 HashMap。
HashMap(int initialCapacity)
构造一个带指定初始容量和默认加载因子 (0.75) 的空 HashMap。
HashMap(int initialCapacity, float loadFactor)
构造一个带指定初始容量和加载因子的空 HashMap。
我们来看一下HashMap(int initialCapacity, float loadFactor)构造方法吧[/size]
[img]http://dl2.iteye.com/upload/attachment/0090/8356/1da4d846-0114-304a-b4fa-126d3224c521.png[/img]
[size=small]在这个构造方法中可以看出,HashMap是用一个名为table的数组实现的,其数组元素是Entry,由于数组长度是固定的,而HashMap这种集合肯定是需要长度可变的,所以我们可以看到构造器中有capacity、loadFactor、threshold等几个变量的操作形成一套变换table数组长度的算法。
数组元素Entry到底是什么东西?是不是它使我们可以通过Key定位到Value呢?[/size]
[img]http://dl2.iteye.com/upload/attachment/0090/8362/2fbb46a6-7d2f-3961-aebf-d9d69fdcc6a2.png[/img]
[size=small]Entry好像结构很简单,我们看到了key和value,键值对对应的功能就是出自于这两个家伙。等等我们还看到什么一个名为next的Entry<K,V>变量,这让我们联想起Entry是不是会作为链表元素出现呢?可他已经是数组元素了啊?
好吧,我们来看看HashMap的put方法[/size]
[img]http://dl2.iteye.com/upload/attachment/0090/8372/b78ddce4-fb39-32b0-b032-1449b7005bc4.png[/img]
[size=small]看到他的覆盖条件了吗?两个key的hash值一样还不够,还必须要equal的。读到这边我们就知道hash值相等的两个值可能并不equal。就是说多个不同的元素可能拥有同一hash值,就是说多个不同的元素会在同一个数组元素中。这时我们想到了前面的Entry的next变量。看到覆盖处理中for循环的迭代条件for (Entry<K,V> e = table[i]; e != null; e = e.next)与覆盖条件 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) 我们就可以确认,它们确实是用链表实现的。
再让我们来看看它addEntry方法吧,它是怎么处理链表的[/size]
[img]http://dl2.iteye.com/upload/attachment/0090/8380/4abe1ac0-9486-3755-8f87-6509f4e19bdc.png[/img]
[size=small]看到这里大家应该都知道了吧~
HashMap的存储方式用图片来展示一下[/size]
[img]http://dl2.iteye.com/upload/attachment/0090/8385/3e29746c-415a-397c-8503-dde95fc6b202.png[/img]
它的存储方式对我们自己日常开发也有启发作用,就让我们一同来学一些吧~[/size]
[size=small]首先看它的构造方法
HashMap()
构造一个具有默认初始容量 (16) 和默认加载因子 (0.75) 的空 HashMap。
HashMap(int initialCapacity)
构造一个带指定初始容量和默认加载因子 (0.75) 的空 HashMap。
HashMap(int initialCapacity, float loadFactor)
构造一个带指定初始容量和加载因子的空 HashMap。
我们来看一下HashMap(int initialCapacity, float loadFactor)构造方法吧[/size]
[img]http://dl2.iteye.com/upload/attachment/0090/8356/1da4d846-0114-304a-b4fa-126d3224c521.png[/img]
[size=small]在这个构造方法中可以看出,HashMap是用一个名为table的数组实现的,其数组元素是Entry,由于数组长度是固定的,而HashMap这种集合肯定是需要长度可变的,所以我们可以看到构造器中有capacity、loadFactor、threshold等几个变量的操作形成一套变换table数组长度的算法。
数组元素Entry到底是什么东西?是不是它使我们可以通过Key定位到Value呢?[/size]
[img]http://dl2.iteye.com/upload/attachment/0090/8362/2fbb46a6-7d2f-3961-aebf-d9d69fdcc6a2.png[/img]
[size=small]Entry好像结构很简单,我们看到了key和value,键值对对应的功能就是出自于这两个家伙。等等我们还看到什么一个名为next的Entry<K,V>变量,这让我们联想起Entry是不是会作为链表元素出现呢?可他已经是数组元素了啊?
好吧,我们来看看HashMap的put方法[/size]
[img]http://dl2.iteye.com/upload/attachment/0090/8372/b78ddce4-fb39-32b0-b032-1449b7005bc4.png[/img]
[size=small]看到他的覆盖条件了吗?两个key的hash值一样还不够,还必须要equal的。读到这边我们就知道hash值相等的两个值可能并不equal。就是说多个不同的元素可能拥有同一hash值,就是说多个不同的元素会在同一个数组元素中。这时我们想到了前面的Entry的next变量。看到覆盖处理中for循环的迭代条件for (Entry<K,V> e = table[i]; e != null; e = e.next)与覆盖条件 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) 我们就可以确认,它们确实是用链表实现的。
再让我们来看看它addEntry方法吧,它是怎么处理链表的[/size]
[img]http://dl2.iteye.com/upload/attachment/0090/8380/4abe1ac0-9486-3755-8f87-6509f4e19bdc.png[/img]
[size=small]看到这里大家应该都知道了吧~
HashMap的存储方式用图片来展示一下[/size]
[img]http://dl2.iteye.com/upload/attachment/0090/8385/3e29746c-415a-397c-8503-dde95fc6b202.png[/img]