天天躁日日躁狠狠躁AV麻豆-天天躁人人躁人人躁狂躁-天天澡夜夜澡人人澡-天天影视香色欲综合网-国产成人女人在线视频观看-国产成人女人视频在线观看

Java中對HashMap的深度分析

Java的世界里,無論類還是各種數(shù)據(jù),其結(jié)構(gòu)的處理是整個程序的邏輯以及性能的關(guān)鍵。由于本人接觸了一個有關(guān)性能與邏輯同時并存的問題,于是就開始研究這方面的問題。找遍了大大小小的論壇,也把《Java 虛擬機(jī)規(guī)范》,《apress,.Java.collections.(2001),.bm.ocr.6.0.shareconnector》,和《Thinking in Java》翻了也找不到很好的答案,于是一氣之下把JDK的 src 解壓出來研究,擴(kuò)然開朗,遂寫此文,跟大家分享感受和順便驗證我理解還有沒有漏洞。 這里就拿HashMap來研究吧。

  HashMap可謂JDK的一大實用工具,把各個Object映射起來,實現(xiàn)了“鍵--值”對應(yīng)的快速存取。但實際里面做了些什么呢?

  在這之前,先介紹一下負(fù)載因子和容量的屬性。大家都知道其實一個 HashMap 的實際容量就 因子*容量,其默認(rèn)值是 16×0.75=12; 這個很重要,對效率很一定影響!當(dāng)存入HashMap的對象超過這個容量時,HashMap 就會重新構(gòu)造存取表。這就是一個大問題,我后面慢慢介紹,反正,如果你已經(jīng)知道你大概要存放多少個對象,最好設(shè)為該實際容量的能接受的數(shù)字。

  兩個關(guān)鍵的方法,put和get:

  先有這樣一個概念,HashMap是聲明了 Map,Cloneable, Serializable 接口,和繼承了 AbstractMap 類,里面的 Iterator 其實主要都是其內(nèi)部類HashIterator 和其他幾個 iterator 類實現(xiàn),當(dāng)然還有一個很重要的繼承了Map.Entry 的 Entry 內(nèi)部類,由于大家都有源代碼,大家有興趣可以看看這部分,我主要想說明的是 Entry 內(nèi)部類。它包含了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);

  這連續(xù)的兩步就是 HashMap 最牛的地方!研究完我都汗顏了,其中 hash 就是通過 key 這個Object的 hashcode 進(jìn)行 hash,然后通過 indexFor 獲得在Object table的索引值。

  table???不要驚訝,其實HashMap也神不到哪里去,它就是用 table 來放的。最牛的就是用 hash 能正確的返回索引。其中的hash算法,我跟JDK的作者 Doug 聯(lián)系過,他建議我看看《The art of programing vol3》可恨的是,我之前就一直在找,我都找不到,他這樣一提,我就更加急了,可惜口袋空空啊?。?!

  不知道大家有沒有留意 put 其實是一個有返回的方法,它會把相同鍵值的 put 覆蓋掉并返回舊的值!如下方法徹底說明了 HashMap 的結(jié)構(gòu),其實就是一個表加上在相應(yīng)位置的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; //把新的值賦予給對應(yīng)鍵值。
  e.recordAccess(this); //空方法,留待實現(xiàn)
  return oldvalue; //返回相同鍵值的對應(yīng)的舊的值。
  }
  }
  modCount++; //結(jié)構(gòu)性更改的次數(shù)
  addEntry(hash, k, value, i); //添加新元素,關(guān)鍵所在!
  return null; //沒有相同的鍵值返回
  }

  我們把關(guān)鍵的方法拿出來分析:

  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,那它經(jīng)過indexfor之后的索引一定都為i,這樣在new的時候這個Entry的next就會指向這個原本的table[i],再有下一個也如此,形成一個鏈表,和put的循環(huán)對定e.next獲得舊的值。到這里,HashMap的結(jié)構(gòu),大家也十分明白了吧?

  if (size++ >= threshold) //這個threshold就是能實際容納的量
  resize(2 * table.length); //超出這個容量就會將Object table重構(gòu)

  所謂的重構(gòu)也不神,就是建一個兩倍大的table(我在別的論壇上看到有人說是兩倍加1,把我騙了),然后再一個個indexfor進(jìn)去!注意!!這就是效率??!如果你能讓你的HashMap不需要重構(gòu)那么多次,效率會大大提高!

  說到這里也差不多了,get比put簡單得多,大家,了解put,get也差不了多少了。對于collections我是認(rèn)為,它是適合廣泛的,當(dāng)不完全適合特有的,如果大家的程序需要特殊的用途,自己寫吧,其實很簡單。(作者是這樣跟我說的,他還建議我用LinkedHashMap,我看了源碼以后發(fā)現(xiàn),LinkHashMap其實就是繼承HashMap的,然后override相應(yīng)的方法,有興趣的同人,自己looklook)建個 Object table,寫相應(yīng)的算法,就ok啦。

  舉個例子吧,像 Vector,list 啊什么的其實都很簡單,最多就多了的同步的聲明,其實如果要實現(xiàn)像Vector那種,插入,刪除不多的,可以用一個Object table來實現(xiàn),按索引存取,添加等。

  如果插入,刪除比較多的,可以建兩個Object table,然后每個元素用含有next結(jié)構(gòu)的,一個table存,如果要插入到i,但是i已經(jīng)有元素,用next連起來,然后size++,并在另一個table記錄其位置。

jsp技術(shù)Java中對HashMap的深度分析,轉(zhuǎn)載需保留來源!

鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請第一時間聯(lián)系我們修改或刪除,多謝。

主站蜘蛛池模板: 亚洲欧美日韩国产精品26u | 大胸美女被吊起来解开胸罩 | 无套暴躁白丝秘书 | 亚洲欧美日韩在线观看一区二区三区 | 久久久久久久久久毛片精品美女 | 武侠艳妇屈辱的张开双腿 | 老鸭窝毛片 | 后入式啪gif动态图 后入式狂顶免费视频 | 在线精品国精品国产不卡 | 秋霞电影网午夜一级鲁丝片 | 亚洲中文久久久久久国产精品 | 最新国产在线视频 | 强行撕开衣服捏胸黄文 | 久久黄色网址 | 国产亚洲AV精品无码麻豆 | 97亚洲狠狠色综合久久位 | 中文字幕一区二区视频 | 亚洲无码小格式 | 美美哒免费影视8 | 99热国产这里只有精品6 | 中国xxxxxz | 超碰最新网站 | 纯肉高H啪短文合集 | 亚洲看片网站 | 中国少妇内射XXXHD免费 | 在线看片韩国免费人成视频 | 欧美高清一区二区三 | 国产香蕉视频在线播放 | 老少配xxxxx欧美 | 色呦呦导航 | 伊人久久大香线蕉综合99 | 免费观看国产视频 | 亚洲AV怡红院影院怡春院 | 国产精品高清m3u8在线播放 | 1a级毛片免费观看 | 99日影院在线播放 | 少妇久久久久久被弄高潮 | 国产精品毛片AV久久97 | 亚洲AV久久无码精品九号软件 | 大陆女人内谢69XXXORG | 湖南张丽大战黑人hd视频 |