当前位置:七道奇文章资讯编程技术Java编程
日期:2011-03-22 16:16:00  来源:本站整理

Java中对HashMap的深度解析与比较[Java编程]

赞助商链接



  本文“Java中对HashMap的深度解析与比较[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的构造,大家也十清楚白了吧?

if (size++ >= threshold) //这个threshold就是能实际包容的量

resize(2 * table.length); //超越这个容量就会将Object table重构

所谓的重构也不神,就是建一个两倍大的table(我在别的论坛上看到有人说是两倍加1,把我骗了),然后再一个个indexfor进去!注意!!这就是效率!!假如你能让你的HashMap不需求重构那么多次,效率会大大提高!

说到这里也差不多了,get比put简单得多,大家,理解put,get也差不了多少了.关于collections我是认为,它是合适遍及的,当不完好合适特有的,假如大家的程序需求特别的用处,自己写吧,其实很简单.(作者是这样跟我说的,他还倡议我用LinkedHashMap,我看了源码今后发现,LinkHashMap其实就是担当HashMap的,然后override呼应的办法,有爱好的同人,自己looklook)建个 Object table,写呼应的算法,就ok啦.

举个例子吧,像 Vector,list 啊什么的其实都很简单,最多就多了的同步的声明,其实假如要实现像Vector那种,插入,删除不多的,可以用一个Object table来实现,按索引存取,增添等.

假如插入,删除对比多的,可以建两个Object table,然后每个元素用含有next构造的,一个table存,假如要插入到i,但是i已经有元素,用next连起来,然后size++,并在另一个table记录其位置.


  以上是“Java中对HashMap的深度解析与比较[Java编程]”的内容,如果你对以上该文章内容感兴趣,你可以看看七道奇为您推荐以下文章:
  • 利用Javascript实现网页水印(非图片水印)
  • Java开辟环境的搭建
  • Ubuntu java安装与配置
  • 办理Ubuntu 10.04 Firefox3.6 Java浏览器插件不工作的问
  • Ubuntu重装后Java环境的设置
  • Sun Java进入Ubuntu 10.10软件中央
  • Ubuntu 10.10配置Java开辟环境
  • 在Ubuntu 10.10中配置Java环境变量的办法
  • Ubuntu下Java环境的搭建
  • Ubuntu 10.04 下安装 Java, JRE
  • Ubuntu 10.04下的搭建SUN JAVA开辟环境
  • Ubuntu 12.04安装java7
  • 本文地址: 与您的QQ/BBS好友分享!
    • 好的评价 如果您觉得此文章好,就请您
        0%(0)
    • 差的评价 如果您觉得此文章差,就请您
        0%(0)

    文章评论评论内容只代表网友观点,与本站立场无关!

       评论摘要(共 0 条,得分 0 分,平均 0 分) 查看完整评论
    Copyright © 2020-2022 www.xiamiku.com. All Rights Reserved .