WEB开发网
开发学院WEB开发Jsp Java中对HashMap的深度分析与比较 阅读

Java中对HashMap的深度分析与比较

 2008-01-05 08:21:58 来源:WEB开发网   
核心提示:文本要害字:程序设计/java/入门在Java的世界里,无论类还是各种数据,Java中对HashMap的深度分析与比较,其结构的处理是整个程序的逻辑以及性能的要害,由于本人接触了一个有关性能与逻辑同时并存的问题,和put的循环对定e.next获得旧的值,到这里,于是就开始研究这方面的问题,

文本要害字:程序设计/java/入门

在Java的世界里,无论类还是各种数据,其结构的处理是整个程序的逻辑以及性能的要害。由于本人接触了一个有关性能与逻辑同时并存的问题,于是就开始研究这方面的问题。 找遍了大大小小的论坛,也把《Java 虚拟机规范》,《aPRess,.java.collections.(2001),.bm.ocr.6.0.shareconnector》,和《Thinking in Java》翻了也找不到很好的答案,于是一气之下把JDK的 src 解压出来研究,扩然开朗,遂写此文,跟大家分享感受和顺便验证我理解还有没有漏洞。 这里就拿HashMap来研究吧。

HashMap可谓JDK的一大实用工具,把各个Object映射起来,实现了“键--值”对应的快速存取。但实际里面做了些什么呢?

在这之前,先介绍一下负载因子和容量的属性。大家都知道其实一个 HashMap 的实际容量就 因子*容量,其默认值是 16×0.75=12; 这个很重要,对效率很一定影响!当存入HashMap的对象超过这个容量时,HashMap 就会重新构造存取表。这就是一个大问题,我后面慢慢介绍,反正,假如你已经知道你大概要存放多少个对象,最好设为该实际容量的能接受的数字。

两个要害的方法,put和get:

先有这样一个概念,HashMap是声明了 Map,Cloneable, Serializable 接口,和继续了 AbstractMap 类,里面的 Iterator 其实主要都是其内部类HashIterator 和其他几个 iterator 类实现,当然还有一个很重要的继续了Map.Entry 的 Entry 内部类,由于大家都有源代码,大家有爱好可以看看这部分,我主要想说明的是 Entry 内部类。它包含了hash,value,key 和next 这四个属性,很重要。put的源码如下

public Object put(Object key, Object value) {
Object k = maskNull(key);

这个就是判定键值是否为空,并不很深奥,其实假如为空,它会返回一个static Object 作为键值,这就是为什么HashMap答应空键值的原因。

int hash = hash(k);
int i = indexFor(hash, table.length);

这连续的两步就是 HashMap 最牛的地方!研究完我都汗颜了,其中 hash 就是通过 key 这个Object的 hashcode 进行 hash,然后通过 indexFor 获得在Object table的索引值。

table???不要惊奇,其实HashMap也神不到哪里去,它就是用 table 来放的。最牛的就是用 hash 能正确的返回索引。其中的hash算法,我跟JDK的作者 Doug 联系过,他建议我看看《The art of programing vol3》可恨的是,我之前就一直在找,我都找不到,他这样一提,我就更加急了,可惜口袋空空啊!!!

不知道大家有没有留意 put 其实是一个有返回的方法,它会把相同键值的 put 覆盖掉并返回旧的值!如下方法彻底说明了 HashMap 的结构,其实就是一个表加上在相应位置的Entry的链表:

for (Entry e = table[i]; e != null; e = e.next) {
 if (e.hash == hash && eq(k, e.key)) {
  Object oldvalue = e.value;
  e.value = value; //把新的值赋予给对应键值。
  e.recordaccess(this); //空方法,留待实现
  return oldvalue; //返回相同键值的对应的旧的值。
 }
}
modCount++; //结构性更改的次数
addEntry(hash, k, value, i); //添加新元素,要害所在!
return null; //没有相同的键值返回
}

我们把要害的方法拿出来分析:

void addEntry(int hash, Object key, Object value, int bUCketIndex) {
table[bucketIndex] = new Entry(hash, key, value, table[bucketIndex]);

因为 hash 的算法有可能令不同的键值有相同的hash码并有相同的table索引,如:key=“33”和key=Object g的hash都是-8901334,那它经过indexfor之后的索引一定都为i,这样在new的时候这个Entry的next就会指向这个原本的table[i],再有下一个也如此,形成一个链表,和put的循环对定e.next获得旧的值。到这里,HashMap的结构,大家也十分明白了吧?


Tags:Java HashMap 深度分析

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接