HashMap深度解析(一)
本文来自:高爽|Coder,原文地址:http://blog.csdn.net/ghsau/article/details/16843543
HashMap可以说是Java中最常用的集合类框架之一,是Java语言中非常典型的数据结构,我们总会在不经意间用到它,很大程度上方便了我们日常
开发。在很多Java的笔试题中也会被问到,最常见的,“HashMap和HashTable有什么区别?”,这也不是三言两语能说清楚的,这种笔试题就
是考察你来笔试之前有没有复习功课,随便来个快餐式的复习就能给出简单的答案。
HashMap计划写两篇文章,一篇是HashMap工作原理,也就是本文,另一篇是多线程下的HashMap会引发的问题。这一年文章写的有点少,工
作上很忙,自己业余时间也做点东西,就把博客的时间占用了,以前是力保一周一篇文章,有点给自己任务的意思,搞的自己很累,文章质量也不高,有时候写技术
文章也是需要灵感的,为了举一个例子可能要绞尽脑汁,为了一段代码可能要验证好多次,现在想通了,有灵感再写,需要一定的积累,才能把自己了解的知识点总
结归纳成文章。
言归正传,了解HashMap之前,我们需要知道Object类的两个方法hashCode和equals,我们先来看一下这两个方法的默认实现:
- /** JNI,调用底层其它语言实现 */
- public native int hashCode();
- /** 默认同==,直接比较对象 */
- public boolean equals(Object obj) {
- return (this == obj);
- }
equals方法我们太熟悉了,我们经常用于字符串比较,String类中重写了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。
和 y 引用同一个对象时,此方法才返回 true(x == y 具有值 true)。 当此方法被重写时,通常有必要重写 hashCode
方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。
- 在 Java 应用程序执行期间,在同一对象上多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是对象上 equals 比较中所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
- 如果根据 equals(Object) 方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。
- 以
下情况不 是必需的:如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么在两个对象中的任一对象上调用
hashCode 方法必定会生成不同的整数结果。但是,程序员应该知道,为不相等的对象生成不同整数结果可以提高哈希表的性能。
当我们看到实现这两个方法有这么多要求时,立刻凌乱了,幸好有IDE来帮助我们,Eclipse中可以通过快捷键alt+shift+s调出快捷菜单,
选择Generate hashCode() and
equals(),根据业务需求,勾选需要生成的属性,确定之后,这两个方法就生成好了,我们通常需要在JavaBean对象中重写这两个方法。
好了,这两个方法介绍完之后,我们回到HashMap。HashMap是最常用的集合类框架之一,它实现了Map接口,所以存储的元素也是键值对映射的
结构,并允许使用null值和null键,其内元素是无序的,如果要保证有序,可以使用LinkedHashMap。HashMap是线程不安全的,下篇
文章会讨论。HashMap的类结构如下:
java.util
类 HashMap<K,V>
java.lang.Object
java.util.AbstractMap<K,V>
java.util.HashMap<K,V>
- 所有已实现的接口:
- Serializable,Cloneable,Map<K,V>
- 直接已知子类:
- LinkedHashMap,PrinterStateReasons
- HashMap通过键的hashCode来快速的存取元素。
- 当不同的对象hashCode发生碰撞时,HashMap通过单链表来解决,将新元素加入链表表头,通过next指向原有的元素。单链表在Java中的实现就是对象的引用(复合)。
- 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;
- }
到这里,我们了解了HashMap工作原理的一部分,那还有另一部分,如,加载因子及rehash,HashMap通常的使用规则,多线程并发时HashMap存在的问题等等,这些会留在下一章说明。
HashMap深度解析(一)的更多相关文章
- 转:HashMap深度解析(一)
HashMap哈希码hashCodeequals 本文来自:高爽|Coder,原文地址:http://blog.csdn.net/ghsau/article/details/16843543,转载 ...
- HashMap深度解析(二)
本文来自:高爽|Coder,原文地址:http://blog.csdn.net/ghsau/article/details/16890151 上一篇比较深入的分析了HashMap在put元素时的整体过 ...
- HashMap深度解析
最基本的结构就是两种,一种是数组,一种是模拟指针(引用),所有的数据结构都可以用这两个基本结构构造,HashMap也一样.当程序试图将多个 key-value 放入 HashMap 中时,以如下代码片 ...
- HashMap深度解析(转载)
原文地址:http://blog.csdn.net/ghsau/article/details/16890151 实现原理:用一个数组来存储元素,但是这个数组存储的不是基本数据类型.HashMap实现 ...
- HashMap深度解析(二)
本文来自:高爽|Coder,原文地址:http://blog.csdn.net/ghsau/article/details/16890151,转载请注明. 上一篇比较深入的分析了HashM ...
- HashMap深度解析(一)
HashMap可以说是Java中最常用的集合类框架之一,是Java语言中非常典型的数据结构,我们总会在不经意间用到它,很大程度上方便了我们日常 开发.在很多Java的笔试题中也会被问到,最常见的,“H ...
- 深度解析HashMap底层实现架构
摘要:分析Map接口的详细使用以及HashMap的底层是如何实现的? 本文分享自华为云社区<[图文并茂]深度解析HashMap高频面试及底层实现结构![奔跑吧!JAVA]>,原文作者:灰小 ...
- 源码深度解析SpringMvc请求运行机制(转)
源码深度解析SpringMvc请求运行机制 本文依赖的是springmvc4.0.5.RELEASE,通过源码深度解析了解springMvc的请求运行机制.通过源码我们可以知道从客户端发送一个URL请 ...
- mybatis 3.x源码深度解析与最佳实践(最完整原创)
mybatis 3.x源码深度解析与最佳实践 1 环境准备 1.1 mybatis介绍以及框架源码的学习目标 1.2 本系列源码解析的方式 1.3 环境搭建 1.4 从Hello World开始 2 ...
随机推荐
- 如何从代码层防御10大安全威胁中的 Xpath Injection?
普遍性和可检测性: Xpath 注入是 OWASP TOP10 安全威胁中 A1 Injection 中的一种,注入漏洞发生在应用程序将不可信的数据发送到解释器时.虽然注入漏洞很容易通过审查代码发现, ...
- Shoot the Bullet
zoj3229:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3442 题意:一个摄影师,在n天内给m个女神拍照.每个女神至少要 ...
- QiQi and Symmerty
http://sdu.acmclub.com/index.php?app=problem_title&id=961&problem_id=23772 题意:给出一个01串,问有多少个子 ...
- 11.在Global的Application_Error处理错误示例
Application_Error是在程序出问题时触发的事件. 这里面要用到错误页的情况,所以要配置web.config的customError项. 1.建立Global文件,在它的Applicati ...
- vs2008 提示msdbg.dll未正确安装的解决办法
开始-->运行-->输入: regsvr32.exe "%ProgramFiles(x86)%\Common Files\Microsoft Shared\VS7Debug\ms ...
- 转-----实现基本的Ajax和Json请求
前面已经封装好了一个方法ajax(),通过这个方法可以实现Ajax请求,接下来就是给出 例程来测试这个方法和实现简单的功能. 视图的部分代码如下: 1 2 3 4 5 6 7 8 9 <bo ...
- (转载)Mysql查找如何判断字段是否包含某个字符串
(转载)http://www.th7.cn/db/mysql/201306/31159.shtml 有这样一个需求,在Mysql数据库字符串字段(权限)中,用户有多个不同的邮箱,分别被‘,’分开,现在 ...
- UIView hitTest的原理
[转自:http://blog.sina.com.cn/s/blog_59fb90df0101ab26.html] UIView 两个方法: - (UIView *)hitTest:(CGPoint) ...
- Eclipse添加快速查找Dao中方法所对应的Mybatis XML映射SQL的插件
Dao关联Mybatis快速查找的插件安装地址:http://dl.bintray.com/harawata/eclipse 安装步骤: ①Eclipse ==> Help ==> Ins ...
- JavaScript高级程序设计19.pdf
注册处理程序 navigator.registerContentHandler("applicat/rss+xml","http://www.somereader.com ...