看了不少关于HaskMap工作原理的博客,下面自己总结记录一下:

1.了解HashMap之前,需要知道Object类的两个方法:hashCode和equals;

默认实现方法:

/** JNI,调用底层其它语言实现 */
public native int hashCode(); /** 默认同==,直接比较对象 */
public boolean equals(Object obj) {
return (this == obj);
}

equals方法我们比较熟悉的,经常用于比较字符串,源码实现:

public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String) anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
// 逐个判断字符是否相等
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}

重写equals要满足几个条件:

  • 自反性:对于任何非空引用值 x,x.equals(x) 都应返回 true。
  • 对称性:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true。
  • 传递性:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 应返回 true。
  • 一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是对象上 equals 比较中所用的信息没有被修改。
  • 对于任何非空引用值 x,x.equals(null) 都应返回 false。
下面来说说hashCode方法,这个方法我们平时通常是用不到的,它是为哈希家族的集合类框架(HashMap、HashSet、HashTable)提供服务,hashCode 的常规协定是:
  • 在 Java 应用程序执行期间,在同一对象上多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是对象上 equals 比较中所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
  • 如果根据 equals(Object) 方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。
  • 以下情况不 是必需的:如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么在两个对象中的任一对象上调用 hashCode 方法必定会生成不同的整数结果。但是,程序员应该知道,为不相等的对象生成不同整数结果可以提高哈希表的性能。

HashMap中我们最长用的就是put(K, V)和get(K)。我们都知道,HashMap的K值是唯一的,那如何保证唯一性呢?我们首先想到的是用equals比较,没错,这样可以实现,但随着内部元素的增多,put和get的效率将越来越低,这里的时间复杂度是O(n),假如有1000个元素,put时需要比较1000次。实际上,HashMap很少会用到equals方法,因为其内通过一个哈希表管理所有元素,哈希是通过hash单词音译过来的,也可以称为散列表,哈希算法可以快速的存取元素,当我们调用put存值时,HashMap首先会调用K的hashCode方法,获取哈希码,通过哈希码快速找到某个存放位置,这个位置可以被称之为bucketIndex,通过上面所述hashCode的协定可以知道,如果hashCode不同,equals一定为false,如果hashCode相同,equals不一定为true。所以理论上,hashCode可能存在冲突的情况,有个专业名词叫碰撞,当碰撞发生时,计算出的bucketIndex也是相同的,这时会取到bucketIndex位置已存储的元素,最终通过equals来比较,equals方法就是哈希码碰撞时才会执行的方法,所以前面说HashMap很少会用到equals。HashMap通过hashCode和equals最终判断出K是否已存在,如果已存在,则使用新V值替换旧V值,并返回旧V值,如果不存在 ,则存放新的键值对<K, V>到bucketIndex位置。

 现在我们知道,执行put方法后,最终HashMap的存储结构会有这三种情况,情形3是最少发生的,哈希码发生碰撞属于小概率事件。到目前为止,我们了解了两件事:
  • HashMap通过键的hashCode来快速的存取元素。
  • 当不同的对象hashCode发生碰撞时,HashMap通过单链表来解决,将新元素加入链表表头,通过next指向原有的元素。单链表在Java中的实现就是对象的引用(复合)。
       来鉴赏一下HashMap中put方法源码:
public V put(K key, V value) {
// 处理key为null,HashMap允许key和value为null
if (key == null)
return putForNullKey(value);
// 得到key的哈希码
int hash = hash(key);
// 通过哈希码计算出bucketIndex
int i = indexFor(hash, table.length);
// 取出bucketIndex位置上的元素,并循环单链表,判断key是否已存在
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;
}
} // key不存在时,加入新元素
modCount++;
addEntry(hash, key, value, i);
return null;
}

本文来自:高爽|Coder,原文地址:http://blog.csdn.net/ghsau/article/details/16843543,转载请注明。

HashMap工作原理总结的更多相关文章

  1. Java HashMap工作原理及实现

    Java HashMap工作原理及实现 2016/03/20 | 分类: 基础技术 | 0 条评论 | 标签: HASHMAP 分享到:3 原文出处: Yikun 1. 概述 从本文你可以学习到: 什 ...

  2. HashMap工作原理(转载)

    转载自:http://www.importnew.com/7099.html  HashMap的工作原理是近年来常见的Java面试题.几乎每个Java程序员都知道HashMap,都知道哪里要用Hash ...

  3. 【Java基础】HashMap工作原理

    HashMap Hash table based implementation of the Map interface. This implementation provides all of th ...

  4. HashMap工作原理 和 HashTable

    原文链接: Javarevisited 翻译: ImportNew.com - 唐小娟 译文链接: http://www.importnew.com/7099.html 你用过HashMap吗 譬如H ...

  5. Java HashMap工作原理及实现[转]

    原文:http://yikun.github.io/2015/04/01/Java-HashMap%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86%E5%8F%8A%E5%AE ...

  6. 160706、Java HashMap工作原理及实现

    1. 概述 从本文你可以学习到: 什么时候会使用HashMap?他有什么特点? 你知道HashMap的工作原理吗? 你知道get和put的原理吗?equals()和hashCode()的都有什么作用? ...

  7. HashMap工作原理的介绍!

    HashMap的工作原理是近年来常见的Java面试题.几乎每个Java程序员都知道HashMap,都知道哪里要用HashMap,知道HashTable和HashMap之间的区别,那么为何这道面试题如此 ...

  8. Java HashMap工作原理:不仅仅是HashMap

    前言: 几乎所有java程序员都用过hashMap,但会用不一定会说. 近年来hashMap是非常常见的面试题,如何为自己的回答加分?需要从理解开始. "你用过hashMap吗?" ...

  9. Java HashMap工作原理及实现(转载)

    https://yikun.github.io/2015/04/01/Java-HashMap工作原理及实现/

随机推荐

  1. 04 MySQL之函数

    01-数学函数 数学函数主要用来处理数值数据. # 1.绝对值函数 ABS(x) 和 返回圆周率的函数 PI() ABS(x) 返回x的绝对值. 例: mysql> select ABS(2), ...

  2. div固定在浏览器的最上方,不随滚动条滚动

    #topDIV { position: fixed; ; ; width: 100%; height: 35px; border-bottom: 1px solid #eee; background- ...

  3. springmvc集成swagger

    1.保证项目为maven项目 2.导入jar包依赖 <dependency> <groupId>io.springfox</groupId> <artifac ...

  4. COALESCE关键字的使用

    COALESCE是sql标准里面的一个关键字,我们可以和聚合函数sum,count,max等一起使用完成一些特殊的功能. 以下sql语句基于mysql 1.查询某一个列总和,如果没有数据或者NULL返 ...

  5. flask(1.0)

    目录 一. 关于KeyError和IndexError 二. Python三大主流框架对比 三. flask基础 1.安装flask 2.用flask写出的第一个页面 3.Flask的Response ...

  6. 【Zookeeper】利用zookeeper搭建Hdoop HA高可用

    HA概述 所谓HA(high available),即高可用(7*24小时不中断服务). 实现高可用最关键的策略是消除单点故障.HA严格来说应该分成各个组件的HA机制:HDFS的HA和YARN的HA. ...

  7. 一篇文章搞懂android存储目录结构

    前言 前两天因为开发一个app更新的功能,我将从服务器下载的apk文件放在了内部存储目录(测试手机为小米,路径为:data/user/0/packagename/files)下面,然后安装的时候一直安 ...

  8. Docker知识点总结

    一. docker介绍: 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化.容器是完全使用沙箱机制,相互之间不 ...

  9. 在openstack中安装mysql5.7

    在控制节点上执行 1.下载mysql二进制安装包和依赖包 wget http://mirror.centos.org/centos/7/os/x86_64/Packages/libaio-devel- ...

  10. 【miscellaneous】单播、广播和多播IP地址

    转自:http://www.cnblogs.com/gaoxing/archive/2012/02/19/2358484.html 除地址类别外,还可根据传输的消息特征将IP地址分为单播.广播或多播. ...