【JDK源码阅读8-util】Map接口----HashMap

HashMap是一个基于哈希表的Map接口实现,其结构包括数组和链表,用于键值对存储。HashMap非同步,允许null键值。在HashMap中,通过key的hashCode找到桶位置,如果发生哈希冲突,会形成链表。当HashMap达到一定负载因子(默认0.75)时,会进行扩容。插入和获取元素主要涉及put和get方法,同时要求键对象需正确重写equals()和hashCode()方法。HashMap在解决哈希冲突时使用链地址法。在面试中,常讨论为何String和Integer适合作为键,以及HashMap与ConcurrentHashMap的区别。
摘要由CSDN通过智能技术生成

                                                   HashMap

         HashMap要聊的东西太多了,而且由于HashSet接口中底层实现就是用的HashMap,所以建议先看HashMap的源码。这里就直接转载别人的文章中的总结;毕竟别人总结 的非常到位。先说下结构,对HashMap的结构有个大概的了解后,再说些其工作原理以及其中涉及到的哈希算法。

            参考:【http://blog.csdn.net/qq_27093465/article/details/52207152】

public class HashMap<K,V>
 
 
  
  extends 
  
  AbstractMap<K,V>
 
 
 
 
  
  implements 
  
  Map<K,V>, 
  
  Cloneable, 
  
  Serializable
 
 


数组的特点是:寻址容易,插入和删除困难;而链表的特点是:寻址困难,插入和删除容易。那么我们能不能

综合两者的特性,做出一种寻址容易,插入删除也容易的数据结构?答案是肯定的,这就是我们要提起的哈希表。

HashMap实现了Map接口,继承AbstractMap。其中Map接口定义了键映射到值的规则,而AbstractMap类提供

Map 接口的骨干实现,以最大限度地减少实现此接口所需的工作。


一 HashMap结构

上图  可能很直观清晰的介绍了HashMap的结构:从上图我们可以发现哈希表是由数组+链表组成的,HashMap其实也是一个线性的数组实现的,所以可以理解为其存储数据的容器就是一个线性数组。这可能让我们很不解,一个线性的数组怎么实现按键值对来存取数据呢?


1 .首先HashMap里面实现一个静态内部类Entry,其重要的属性有 key , value, next,从属性key,value。

我们就能很明显的看出来Entry就是HashMap键值对实现的一个基础bean,我们上面说到HashMap的基础就是一个线性数组,

这个数组就是Entry[],Map里面的内容都保存在Entry[]里面。

static class Entry<K,V> implements Map.Entry<K,V> {
	        final K key;//键
	        V value;//值
	        Entry<K,V> next;//下个元素指针
	        int hash;//key的hash值
}

       

        2 两个概念:

1).这里面有个Hash冲突的概念就像上面的一个数组的位置上出现了一条链,即一个链表的出现,这就是所谓的

hash冲突,解决hash冲突,就是让链表的长度变短,或者干脆就是不产生链表,一个好的hash算法应该是让数据很好的

散列到数组的各个位置,即一个位置存一个数据就是最好的散列,下面说的链地址法,说的就是在hashmap里面冲突的时候,

一个节点可以存多个数据。

        2).还有个桶:bucket,就是上面的数组的每一个成员,数组的每个位置就叫一个桶。对应前面的单词。


二 HashMap基本定义

 HashMap也是我们使用非常多的Collection,它是基于哈希表的 Map 接口的实现,以key-value的形式存在。

HashMap可以接受null键值和值,而HashTable则不能;HashMap是非synchronized;HashMap很快;HashMap储存的是键值对。


三 构造函数

HashMap提供了三个构造函数:

     HashMap():构造一个具有默认初始容量 (16) 和默认加载因子 (0.75) 的空 HashMap。

     HashMap(int initialCapacity):构造一个带指定初始容量和默认加载因子 (0.75) 的空 HashMap。

     HashMap(int initialCapacity, float loadFactor):构造一个带指定初始容量和加载因子的空 HashMap。

       在这里提到了两个参数:初始容量,加载因子。这两个参数是影响HashMap性能的重要参数,其中容量表示哈希表中桶的数量,初始容量是创建哈希表时的容量,加载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度,它衡量的是一个散列表的空间的使用程度,负载因子越大表示散列表的装填程度越高,反之愈小。

        对于使用链表法的散列表来说,查找一个元素的平均时间是O(1+a),因此如果负载因子越大,对空间的利用更充分,然而后果是查找效率的降低;如果负载因子太小,那么散列表的数据将过于稀疏,对空间造成严重浪费。系统默认负载因子为0.75,一般情况下我们是无需修改的。


四、工作原理

1 存储的实现put(K key,V value)

        核心就是:根据key的hashcode得到桶的位置,往里面添加值;若发现有对应的键存在就覆盖。

        当我们想一个HashMap中添加一对key-value时,系统首先会计算key的hash值,然后根据hash值确认在table中存储的位置。若该位置没有元素,则直接插入。否则迭代该处元素链表并依此比较其key的hash值。如果两个hash值相等且key值相等(e.hash == hash && ((k = e.key) == key || key.equals(k))),则用新的Entry的value覆盖原来节点的value。如果两个hash值相等但key值不等 ,则将该节点插入该链表的链头。

       ①首先判断key==null?,若为null,就调用putForNullKey方法。

       ②若 key != null ,对key调用hashCode()方法,根据hash值确认在table中存储的位置,即桶的位置,确定数据要插入到那个桶中(bucket位置来储存Entry对象)。

      若桶中有元素,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值