多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國(guó)內(nèi)最全I(xiàn)T社區(qū)平臺(tái) 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁(yè) > php開(kāi)源 > php教程 > java中的HashMap解析

java中的HashMap解析

來(lái)源:程序員人生   發(fā)布時(shí)間:2015-04-13 08:42:19 閱讀次數(shù):4157次

這篇文章準(zhǔn)備從源碼的角度帶大家分析1下java中的hashMap的原理,在了解源碼之前,我們先根據(jù)自己的理解創(chuàng)建1個(gè)hashMap。

先說(shuō)明1下創(chuàng)建的具體原理是這樣的,所謂hashMap,必定是用hash方法來(lái)辨別不同的key值。學(xué)過(guò)hash的都知道,我們解決hash沖突的1種方法就是使用散列和桶,首先肯定所在的桶號(hào),然后在桶里面逐一查找。其實(shí)我們也能夠單純使用數(shù)組實(shí)現(xiàn)map,使用散列是為了取得更高的查詢效力。

要寫(xiě)自己的hashmap前,必須說(shuō)明1下兩個(gè)方法,就是hashcode()和equals()方法,要在map里面判斷兩個(gè)key是不是相等,關(guān)鍵在于這個(gè)兩個(gè)函數(shù)的返回值1定要相等(只有1個(gè)相等是沒(méi)有用的,由于hashmap會(huì)先根據(jù)hashcode()方法查找桶,然后根據(jù)equals()方法獲得value)

如果我們沒(méi)有復(fù)寫(xiě)這個(gè)兩個(gè)方法,object類是根據(jù)類所在內(nèi)存地址來(lái)產(chǎn)生hashcode的,所以1般比較是不會(huì)相同的,又正由于這樣,我們?cè)谑褂米约簶?gòu)造的類當(dāng)key值的時(shí)候,有時(shí)是有必要復(fù)寫(xiě)這兩個(gè)方法的。下面是1個(gè)例子

class myClass{ int i = 0; public myClass(int i) { this.i = i; } @Override public int hashCode() { return i; } @Override public boolean equals(Object obj) { return obj instanceof myClass && i == ((myClass)obj).i; } }

注意上面的instanceof,我們首先要判斷參數(shù)的類是不是相同,這個(gè)非常重要,不過(guò)容易被疏忽。(由于有多是兩個(gè)不同的類,有相同的屬性,連屬性值都相同,這樣我們判斷就會(huì)失誤了)。另外我們要注意String類型重載了這兩個(gè)方法,所以兩個(gè)new String("aa")是相同的

在以下類中,我使用了1個(gè)arraylist來(lái)充當(dāng)鏈,首先我們來(lái)看1個(gè)鍵值對(duì)類,用來(lái)保存鍵和值,這個(gè)是1個(gè)內(nèi)部類,還有要實(shí)現(xiàn)hashmap必須先繼承1個(gè)AbstractMap<K,V>的抽象類

import java.util.AbstractMap; import java.util.ArrayList; import java.util.Map; import java.util.Set; public class MyHashMap<K, V> extends AbstractMap<K, V> { //鏈表長(zhǎng)度 final static int SIZE = 999; private List<K> keys = new ArrayList<K>();     private List<V> values = new ArrayList<V>();  /** * Entry類,用于保存鍵值對(duì) * @author Administrator * * @param <K> * @param <V> */ static class MyEntry<K,V> implements Map.Entry<K, V>{ private K key; private V value; public MyEntry(K key,V value) { this.key = key; this.value = value; } @Override public K getKey() { return key; } @Override public V getValue() { return value; } @Override public V setValue(V v) { V oldValue = value; value = v; return oldValue; } @Override public int hashCode() { //使用key和value的hashcode共同構(gòu)造新的hashcode return (key==null?0:key.hashCode())^(value==null?0:value.hashCode()); } @Override public boolean equals(Object obj) { //注意要檢查類型是不是相同 if(!(obj instanceof MyEntry)) return false; MyEntry en = (MyEntry)obj; //注意空值的情況 return (key==null?en.getKey()==key:key.equals(en.getKey())) && (value==null?en.getKey()==value:value.equals(en.getValue())); } } @SuppressWarnings("unchecked") ArrayList<MyEntry<K,V>>[] buckets = new ArrayList[SIZE]; @Override public Set<java.util.Map.Entry<K, V>> entrySet() { // TODO Auto-generated method stub return null; } }
對(duì)上面的鍵值對(duì)類MyEntry,我們要實(shí)現(xiàn)1個(gè)接口Map.Entry,由于我們1般使用hashmap都可以取得它的Entryset,繼承這個(gè)類正是為了這個(gè)做準(zhǔn)備


接下來(lái)我們先來(lái)實(shí)現(xiàn)put方法

/**      * put方法      */     public V put(K key,V value){         //原值用于返回         V oldValue = null;         //避免越界         int index = Math.abs(key.hashCode())%SIZE;         //檢查是不是有桶,沒(méi)有創(chuàng)建1個(gè)         if(buckets[index]==null){             buckets[index] = new ArrayList<MyEntry<K,V>>();         }         ArrayList<MyEntry<K,V>> bucket = buckets[index];         //創(chuàng)建鍵值對(duì)對(duì)象entry         MyEntry<K, V> pair = new MyEntry<K, V>(key, value);         boolean found = false;         ListIterator<MyEntry<K, V>> it = bucket.listIterator();         //遍歷桶         while(it.hasNext()){             MyEntry<K, V> iPair = it.next();             //如果已在map里面,更新             if(iPair.getKey().equals(key)){                 oldValue = iPair.getValue();                 it.set(pair);                 values.set(keys.indexOf(key),value);                         found = true;                 break;             }         }         //不在map里面,新增         if(!found){             keys.add(key);             values.add(value);             bucket.add(pair);         }         return oldValue;     }

這上面的思路應(yīng)當(dāng)說(shuō)是非常清晰,首先查找桶,沒(méi)有則新建,然后在桶里面查找key值,如果已存在map里面了,更新,否則新增。

再來(lái)看get方法,就更加清晰了

/** * get方法 */ public V get(Object key){ int index = Math.abs(key.hashCode())%SIZE; if(buckets[index]==null) return null; for(MyEntry<K, V> pair:buckets[index]){ if(pair.getKey().equals(key)){ return pair.getValue(); } } return null; }
上面首先查找對(duì)應(yīng)桶,沒(méi)有返回null,如果有則在桶內(nèi)遍歷查找

最后再來(lái)看1下entrySet類

private class MyEntrySet extends AbstractSet<Map.Entry<K, V>>{         @Override         public Iterator<java.util.Map.Entry<K, V>> iterator() {             return new Iterator<java.util.Map.Entry<K, V>>() {                 private int index = ⑴;                 boolean canRemove;                 @Override                 public boolean hasNext() {                     return index<keys.size()⑴;                                     }                 @Override                 public MyEntry<K, V> next() {                     boolean canRemove = true;                     ++index;                                         return new MyEntry<K, V>(keys.get(index), values.get(index));                 }                 @Override                 public void remove() {                     if(!canRemove){                         throw new IllegalStateException();                     }                     canRemove = false;                     keys.remove(index);                     values.remove(index--);                 }             };                     }         @Override         public int size() {                         return keys.size();         }             }
這個(gè)內(nèi)部類主要是為我們提供entry用于外部遍歷使用

下面是完全代碼,大家可以測(cè)試1下

package test; import java.util.AbstractMap; import java.util.AbstractSet; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Set; public class MyHashMap<K, V> extends AbstractMap<K, V> {     //鏈表長(zhǎng)度     final static int SIZE = 999;     private List<K> keys = new ArrayList<K>();     private List<V> values = new ArrayList<V>();          /**      * Entry類,用于保存鍵值對(duì)      * @author Administrator      *      * @param <K>      * @param <V>      */     static class MyEntry<K,V> implements Map.Entry<K, V>{         private K key;         private V value;                  public MyEntry(K key,V value) {             this.key = key;             this.value = value;         }                  @Override         public K getKey() {                         return key;         }         @Override         public V getValue() {                         return value;         }         @Override         public V setValue(V v) {                     V oldValue = value;             value = v;             return oldValue;         }                  @Override         public int hashCode() {             //使用key和value的hashcode共同構(gòu)造新的hashcode             return (key==null?0:key.hashCode())^(value==null?0:value.hashCode());         }                  @Override         public boolean equals(Object obj) {             //注意要檢查類型是不是相同             if(!(obj instanceof MyEntry)) return false;                     MyEntry en = (MyEntry)obj;             //注意空值的情況             return (key==null?en.getKey()==key:key.equals(en.getKey())) &&                     (value==null?en.getKey()==value:value.equals(en.getValue()));         }     }          @SuppressWarnings("unchecked")     ArrayList<MyEntry<K,V>>[] buckets = new ArrayList[SIZE];          /**      * put方法      */     public V put(K key,V value){         //原值用于返回         V oldValue = null;         //避免越界         int index = Math.abs(key.hashCode())%SIZE;         //檢查是不是有桶,沒(méi)有創(chuàng)建1個(gè)         if(buckets[index]==null){             buckets[index] = new ArrayList<MyEntry<K,V>>();         }         ArrayList<MyEntry<K,V>> bucket = buckets[index];         //創(chuàng)建鍵值對(duì)對(duì)象entry         MyEntry<K, V> pair = new MyEntry<K, V>(key, value);         boolean found = false;         ListIterator<MyEntry<K, V>> it = bucket.listIterator();         //遍歷桶         while(it.hasNext()){             MyEntry<K, V> iPair = it.next();             //如果已在map里面,更新             if(iPair.getKey().equals(key)){                 oldValue = iPair.getValue();                 it.set(pair);                 values.set(keys.indexOf(key),value);                         found = true;                 break;             }         }         //不在map里面,新增         if(!found){             keys.add(key);             values.add(value);             bucket.add(pair);         }         return oldValue;     }          /**      * get方法      */     public V get(Object key){         int index = Math.abs(key.hashCode())%SIZE;         if(buckets[index]==null) return null;         for(MyEntry<K, V> pair:buckets[index]){             if(pair.getKey().equals(key)){                 return pair.getValue();             }         }         return null;     }          private class MyEntrySet extends AbstractSet<Map.Entry<K, V>>{         @Override         public Iterator<java.util.Map.Entry<K, V>> iterator() {             return new Iterator<java.util.Map.Entry<K, V>>() {                 private int index = ⑴;                 boolean canRemove;                 @Override                 public boolean hasNext() {                     return index<keys.size()⑴;                                     }                 @Override                 public MyEntry<K, V> next() {                     boolean canRemove = true;                     ++index;                                         return new MyEntry<K, V>(keys.get(index), values.get(index));                 }                 @Override                 public void remove() {                     if(!canRemove){                         throw new IllegalStateException();                     }                     canRemove = false;                     keys.remove(index);                     values.remove(index--);                 }             };                     }         @Override         public int size() {                         return keys.size();         }             }          private MyEntrySet myEntrySet = new MyEntrySet();     @Override     public Set<java.util.Map.Entry<K, V>> entrySet() {                 return myEntrySet;     } }

OK,定義了我們自己hashmap以后,我們?cè)賮?lái)對(duì)比著看源代碼,就比較容易,雖然還有些區(qū)分,但是希望加深大家的理解

首先來(lái)看get方法

/** * Returns the value of the mapping with the specified key. * * @param key * the key. * @return the value of the mapping with the specified key, or {@code null} * if no mapping for the specified key is found. */ public V get(Object key) { //檢查key為null   if (key == null) { HashMapEntry<K, V> e = entryForNullKey; return e == null ? null : e.value; } // Doug Lea's supplemental secondaryHash function (inlined) //利用key的hashcode,計(jì)算新的hash  int hash = key.hashCode(); hash ^= (hash >>> 20) ^ (hash >>> 12); hash ^= (hash >>> 7) ^ (hash >>> 4); //遍歷數(shù)組查找是不是存在對(duì)應(yīng)值 HashMapEntry<K, V>[] tab = table; for (HashMapEntry<K, V> e = tab[hash & (tab.length - 1)]; e != null; e = e.next) { K eKey = e.key; if (eKey == key || (e.hash == hash && key.equals(eKey))) { return e.value; } } return null; }

用源代碼跟我們寫(xiě)的代碼比較,發(fā)現(xiàn)也是先處理null值,源碼中使用了1個(gè)特定的對(duì)象來(lái)代表key為Null的entry

然后是計(jì)算新的hash,這個(gè)怎樣計(jì)算我們不理它,只要知道為了hash更加完善,我們需要根據(jù)key的hashcode重新1次hash值

然后及時(shí)遍歷查找對(duì)應(yīng)value


接下來(lái)看put方法

/** * Maps the specified key to the specified value. * * @param key * the key. * @param value * the value. * @return the value of any previous mapping with the specified key or * {@code null} if there was no such mapping. */ @Override public V put(K key, V value) { //如果新增的key為null,直接返回新生成的1個(gè)特定對(duì)象  if (key == null) { return putValueForNullKey(value); } //重新計(jì)算hash值 int hash = secondaryHash(key.hashCode()); HashMapEntry<K, V>[] tab = table; int index = hash & (tab.length - 1); //遍歷,如果存在就更新 for (HashMapEntry<K, V> e = tab[index]; e != null; e = e.next) { if (e.hash == hash && key.equals(e.key)) { preModify(e); V oldValue = e.value; e.value = value; return oldValue; } } // No entry for (non-null) key is present; create one modCount++; if (size++ > threshold) { tab = doubleCapacity(); index = hash & (tab.length - 1); } //沒(méi)有就新增  addNewEntry(key, value, hash, index); return null; } /** *為控制生產(chǎn)1個(gè)特定對(duì)象 */ private V putValueForNullKey(V value) {         HashMapEntry<K, V> entry = entryForNullKey;         if (entry == null) {             addNewEntryForNullKey(value);             size++;             modCount++;             return null;         } else {             preModify(entry);             V oldValue = entry.value;             entry.value = value;             return oldValue;         }     }
對(duì)照我們的代碼來(lái)看,思路差不多,就是處理null值的時(shí)候有不同
最后來(lái)看我們的entrySet
private final class EntrySet extends AbstractSet<Entry<K, V>> { public Iterator<Entry<K, V>> iterator() { return newEntryIterator(); } public boolean contains(Object o) { if (!(o instanceof Entry)) return false; Entry<?, ?> e = (Entry<?, ?>) o; return containsMapping(e.getKey(), e.getValue()); } public boolean remove(Object o) { if (!(o instanceof Entry)) return false; Entry<?, ?> e = (Entry<?, ?>)o; return removeMapping(e.getKey(), e.getValue()); } public int size() { return size; } public boolean isEmpty() { return size == 0; } public void clear() { HashMap.this.clear(); } }

必須實(shí)現(xiàn)的方法有對(duì)應(yīng)的實(shí)現(xiàn),其中size是另外記錄的1個(gè)變量,用來(lái)記錄數(shù)據(jù)條數(shù)

這個(gè)必須結(jié)合iterator1起看,查找源代碼以后,發(fā)現(xiàn)對(duì)應(yīng)的是這個(gè)class

private final class EntryIterator extends HashIterator implements Iterator<Entry<K, V>> { public Entry<K, V> next() { return nextEntry(); } }
繼承自HashIterator
private abstract class HashIterator { int nextIndex; HashMapEntry<K, V> nextEntry = entryForNullKey; HashMapEntry<K, V> lastEntryReturned; int expectedModCount = modCount; HashIterator() { if (nextEntry == null) { HashMapEntry<K, V>[] tab = table; HashMapEntry<K, V> next = null; while (next == null && nextIndex < tab.length) { next = tab[nextIndex++]; } nextEntry = next; } } public boolean hasNext() { return nextEntry != null; } HashMapEntry<K, V> nextEntry() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); if (nextEntry == null) throw new NoSuchElementException(); HashMapEntry<K, V> entryToReturn = nextEntry; HashMapEntry<K, V>[] tab = table; HashMapEntry<K, V> next = entryToReturn.next; while (next == null && nextIndex < tab.length) { next = tab[nextIndex++]; } nextEntry = next; return lastEntryReturned = entryToReturn; } public void remove() { if (lastEntryReturned == null) throw new IllegalStateException(); if (modCount != expectedModCount) throw new ConcurrentModificationException(); HashMap.this.remove(lastEntryReturned.key); lastEntryReturned = null; expectedModCount = modCount; } }



生活不易,碼農(nóng)辛苦
如果您覺(jué)得本網(wǎng)站對(duì)您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈(zèng)
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 欧美日韩国产亚洲综合不卡 | 亚洲第一网址 | 欧美日韩免费大片 | 99成人| 91最新免费地址入口 | 男女一区二区三区免费 | 国产在线h视频 | 中文字幕在线免费视频 | www.黄色一片 | 日本免费观看网站 | 1区1区3区4区产品亚洲 | 免费黄色福利 | 亚洲精品www久久久久久 | 亚州中文字幕 | 黑人巨大粗xxxxxx | 午夜视频在线免费 | 最近手机中文字幕1 | 免费在线观看视频a | 成人免费看黄页网址大全 | a资源在线 | 在线亚洲日产一区二区 | 性xxx欧美| 欧美极品video粗暴 | 国产成人精品本亚洲 | 精品区| 99久热成人精品视频 | 中国嫩模一级毛片 | 伊人网成人| 三级国产在线观看 | 亚洲精品高清在线观看 | 高清一区在线 | 成人资源在线观看 | 淫视频网站| 一区二区三区久久精品 | 国产精品久久在线观看 | 成人亚洲精品一区二区 | 欧美色欧美亚洲另类二区精品 | 能免费看的黄色网址 | 国产做出在线 | 传媒麻豆 | 97se亚洲综合在线 | 欧美亚洲国产另类 |