关闭

HashMap的基本原理

标签: Java
14人阅读 评论(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),因此如果负载因子越大### ,对空间的利用更充分,然而后果是查找效率的降低;如果负载因子太小,那么散列表的数据将过### 于稀疏,对空间造成严重浪费。

1
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

hash算法 (hashmap 实现原理) Java实现的散列表

1.HashMap的数据结构   数组的特点是:寻址容易,插入和删除困难;而链表的特点是:寻址困难,插入和删除容易。那么我们能不能综合两者的特性,做出一种寻址容易,插入删除也容易的数据结构?答案...
  • u011202334
  • u011202334
  • 2016-05-25 10:12
  • 3366

Java HashMap笔记之一:基本原理

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

HashMap的基本原理与它的线程安全性

http://blog.csdn.net/t894690230/article/details/51323946 1. 前言 能用图说清楚的,就坚决不用代码。能用代码撸清楚的,就坚...
  • z69183787
  • z69183787
  • 2017-04-11 15:45
  • 561

深入理解HashMap(精华必看)

原文地址:http://www.iteye.com/topic/539465     Hashmap是一种非常常用的、应用广泛的数据类型,最近研究到相关的内容,就正好复习一下。网上关于has...
  • jdjdndhj
  • jdjdndhj
  • 2017-01-13 12:00
  • 10829

HashMap的使用方法及注意事项

99、Map(映射):Map 的keySet()方法会返回 key 的集合,因为 Map 的键是不能重复的,因此 keySet()方法的返回类型是 Set;而 Map 的值是可以重复的,因此 valu...
  • u011638419
  • u011638419
  • 2013-09-24 21:00
  • 940

从数组到HashMap之算法解释

一 数组是什么?   忘了在哪本书里曾看到过类似这样的一句话“所有的数据结构都是数组的演化”,想想其实是有道理的,因为计算机的内存其实就是线性的存储空间。   Java示例代码:int[] arr...
  • cwfreebird
  • cwfreebird
  • 2017-01-19 17:20
  • 618

HashMap的那些事

关于HashMap你们肯定不会陌生,它是常用的一种数据类型,在java开发中占据了重要的地位。我觉得这样一个比喻非常的好:HashMap就像一个陶瓷碗,我们经常用到它,却又经常不小心将它摔碎。在一些书...
  • ouyang111222
  • ouyang111222
  • 2015-11-17 22:24
  • 449

hashmap简单实例(个人使用经验)

一、HashMap是错误的:因为int是基本类型,而key和value要求是对象,所以要用Integer而不是int。HashMap的value一定要是Object类型。 二、HashMap Ha...
  • longshenlmj
  • longshenlmj
  • 2015-01-16 11:26
  • 1275

JAVA中HashMap如何删除元素

JAVA中HashMap如何删除元素  java编程语言编程 专业回答 tianheww 2015-09-12 09:56 HashMap的结构是 想要移除某个...
  • evilcry2012
  • evilcry2012
  • 2016-04-11 22:03
  • 10216

使用SparseArray代替HashMap提升性能

SparseArray翻译为稀疏数组,所谓稀疏数组就是数组中大部分的内容值都未被使用(或都为零),在数组中仅有少部分的空间使用。因此造成内存空间的浪费,为了节省内存空间,并且不影响数组中原有的内容值,...
  • hsk256
  • hsk256
  • 2016-02-19 16:17
  • 678
    个人资料
    • 访问:243次
    • 积分:67
    • 等级:
    • 排名:千里之外
    • 原创:6篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条
    文章存档