HashMap的基本原理

标签: Java
43人阅读 评论(0) 收藏 举报
分类:

HashMap的实现原理

概述: HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。

数据结构:HashMap是一个“链表散列”的数据结构,即数组和链表的结合体 hashmap 其实就是一个数组 数组的每个位置放的一个Entry即key-value键值对

当使用put方法时:


public V put(K key, V value) {  
    // HashMap允许存放null键和null值。  
    // 当key为null时,调用putForNullKey方法,将value放置在数组第一个位置。  
    if (key == null)  
        return putForNullKey(value);  
    // 根据key的keyCode重新计算hash值。  
    int hash = hash(key.hashCode());  
    // 搜索指定hash值在对应table中的索引。  
    int i = indexFor(hash, table.length);  
    // 如果 i 索引处的 Entry 不为 null,通过循环不断遍历 e 元素的下一个元素。  
    for (Entry<K,V> e = table[i]; e != null; e = e.next) {  
        Object k;
        //找到指定的key与需要放入的key相比(hash值相同//通过equals比较返回true)
        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {  
            V oldValue = e.value;  
            e.value = value;  
            e.recordAccess(this);  
            return oldValue;  
        }  
    }  
    // 如果i索引处的Entry为null,表明此处还没有Entry。  
    modCount++;  
    // 将key、value添加到i索引处。  
    addEntry(hash, key, value, i);  
    return null;  
} 

上面的代码提供了一个根据hashCode()返回值来计算hash码的方法 hash() 这个方法是一个纯粹的数学计算

    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

对于任意给定的对象,只要他的hashCode()值相同,那么程序调用hash(int h)方法所计算得到的hash码值总是相同的接下来程序会调用indexFor(),来计算该对象应该保存在table数组的哪个索引处:

static int indexFor(int h, int length) {  
    return h & (length-1);  
}  

当程序试图将一个key-value对放入HashMap中时,程序首先根据该 key 的 hashCode() 返回值决定该 Entry 的存储位置:如果两个 Entry 的 key 的 hashCode() 返回值相同,那它们的存储位置相同。如果这两个 Entry 的 key 通过 equals 比较返回 true,新添加 Entry 的 value 将覆盖集合中原有 Entry 的 value,但key不会覆盖。如果这两个 Entry 的 key 通过 equals 比较返回 false,新添加的 Entry 将与集合中原有 Entry 形成 Entry 链,而且新添加的 Entry 位于 Entry 链的头部

当使用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;  
} 

当取值的时候,还是先根据keycode算出在数组的储存位置,然后根据equals取出在Entry链的位置

哈希冲突

当HashMap中的元素越来越多的时候,hash冲突的几率也就越来越高,因为数组的长度是固定的。所以为了提高查询的效率,就要对HashMap的数组进行扩容,数组扩容这个操作也会出现在ArrayList中,这是一个常用的操作,而在HashMap数组扩容之后,最消耗性能的点就出现了:原数组中的数据必须重新计算其在新数组中的位置,并放进去,这就是resize。 那么HashMap什么时候进行扩容呢?当HashMap中的元素个数超过数组大小*loadFactor时,就会进行数组扩容,loadFactor的默认值为0.75,这是一个折中的取值。也就是说,默认情况下,数组大小为16,那么当HashMap中元素个数超过16*0.75=12的时候,就把数组的大小扩展为 2*16=32,即扩大一倍,然后重新计算每个元素在数组中的位置,而这是一个非常消耗性能的操作,所以如果我们已经预知HashMap中元素的个数,那么预设元素的个数能够有效的提高HashMap的性能。

hashmap的性能参数

HashMap的性能参数:

HashMap 包含如下几个构造器:

HashMap():构建一个初始容量为 16,负载因子为 0.75 的 HashMap。

HashMap(int initialCapacity):构建一个初始容量为 initialCapacity,负载因子为 0.75 ### 的HashMap。loadFactor):以指定初始容量、指定的负载因子创建一个 ### HashMap。

HashMap的基础构造器HashMap(int initialCapacity, float ### loadFactor)带有两个参数,它们是初始容量initialCapacity和加载因子loadFactor。 ### initialCapacity:HashMap的最大容量,即为底层数组的长度。

loadFactor:负载因子loadFactor定义为:散列表的实际元素数目(n)/ 散列表的容量(m)。 ### 负载因子衡量的是一个散列表的空间的使用程度,负载因子越大表示散列表的装填程度越高,反之### 愈小。对于使用链表法的散列表来说,查找一个元素的平均时间是O(1+a),因此如果负载因子越大### ,对空间的利用更充分,然而后果是查找效率的降低;如果负载因子太小,那么散列表的数据将过### 于稀疏,对空间造成严重浪费。

查看评论

HashMap基本原理

当HashMap被初始化时,会创建一个Entry数组。数组里每个存储单元可以存放一个Entry, 在Entry对象中包括Key, Value, hash,还有对下一个Entry对象的引用,这样就可以形...
  • Butcher__
  • Butcher__
  • 2017-02-23 22:02:41
  • 134

HashMap及ConcurrentHashMap基本原理概述

0、前言本博文部分文字及图片参考自以下三篇文章,其余内容为本人经过思考及总结后所写,仅作为学习分享使用,如有侵权,请联系本人删除,谢谢。1、什么是HashMap2、高并发下的HashMap3、什么是C...
  • qq906627950
  • qq906627950
  • 2018-03-01 20:40:24
  • 58

HashMap的原理和使用

原文出处:http://www.cnblogs.com/chenssy/p/3521565.html      HashMap也是我们使用非常多的Collection,它是基于哈希表...
  • buptdavid
  • buptdavid
  • 2015-05-27 10:27:13
  • 1320

【图解JDK源码】HashMap的基本原理与它的线程安全性

1. 前言能用图说清楚的,就坚决不用代码。能用代码撸清楚的,就坚决不写解释(不是不写注释哦)。2. 数据结构HashMap内部通过维护一个Entry数组(变量为table),来实现其基本功能,而Ent...
  • t894690230
  • t894690230
  • 2016-05-05 18:06:50
  • 1037

hashmap 实例

  • 2011年08月30日 13:10
  • 23KB
  • 下载

Java HashMap的工作原理 及各种Map区别

一、Java HashMap的工作原理 面试的时候经常会遇见诸如:“java中的HashMap是怎么工作的”,“HashMap的get和put内部的工作原理”这样的问题。 Put : 让我们看下...
  • nanruitao10
  • nanruitao10
  • 2016-08-22 21:05:26
  • 1412

java基础—HashMap实现原理,如何保证HashMap的线程安全?

Java HashMap 是非线程安全的。 在多线程条件下,容易导致死循环,具体表现为CPU使用率100%。因此多线程环境下保证 HashMap 的线程安全性,主要有如下几种方法:   使用 j...
  • ITzhangdaopin
  • ITzhangdaopin
  • 2017-12-05 14:39:11
  • 938

Java HashMap笔记之一:基本原理

摘要: Java中的HashMap是一种简单易用而且高效强大的数据结构,在开发过程中经常使用。这里总结下HashMap的基本原理。HashMap默认内部数组大小?HashMap内部数组为16(JDK7...
  • x380481791
  • x380481791
  • 2017-07-29 09:24:01
  • 133

hashMap的原理 深入理解

首先再次强调hashcode (==)和equals的真正含义(我记得以前有人会说,equals是判断对象内容,hashcode是判断是否相等之类): equals:是否同一个对象实例。注意,是“实...
  • yanlove_jing
  • yanlove_jing
  • 2016-06-11 19:44:27
  • 4460

HashMap的工作原理--重点----数据结构示意图的理解

HashMap的工作原理是近年来常见的Java面试题。几乎每个Java程序员都知道HashMap,都知道哪里要用HashMap,知道HashTable和HashMap之间的区别,那么为何这道面试题如此...
  • qq_27093465
  • qq_27093465
  • 2016-08-15 11:43:20
  • 8178
    个人资料
    持之以恒
    等级:
    访问量: 483
    积分: 68
    排名: 160万+
    文章存档