1. 程式人生 > >thinking in java (十六) ----- 集合之HahsMap(之二)

thinking in java (十六) ----- 集合之HahsMap(之二)

  • get()方法

獲取key相對應的value,實現程式碼如下

public V get(Object key) {
    if (key == null)
        return getForNullKey();
    // 獲取key的hash值
    int hash = hash(key.hashCode());
    // 在“該hash值對應的連結串列”上查詢“鍵值等於key”的元素
    for (Entry<K,V> e = table[indexFor(hash, table.length)];
         e != null;
         e = e.next) {
        Object k;
        if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
            return e.value;
    }
    return null;
}

先判斷是否為null,然後獲取key的雜湊值,最後在該雜湊值對應的連結串列上面查詢鍵值等於key的元

  • put()方法

put對外提供介面,讓HashMap物件可以通過put方法新增KV鍵值對元素

public V put(K key, V value) {
    // 若“key為null”,則將該鍵值對新增到table[0]中。
    if (key == null)
        return putForNullKey(value);
    // 若“key不為null”,則計算該key的雜湊值,然後將其新增到該雜湊值對應的連結串列中。
    int hash = hash(key.hashCode());
    int i = indexFor(hash, table.length);
    for (Entry<K,V> e = table[i]; e != null; e = e.next) {
        Object k;
        // 若“該key”對應的鍵值對已經存在,則用新的value取代舊的value。然後退出!
        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
            V oldValue = e.value;
            e.value = value;
            e.recordAccess(this);
            return oldValue;
        }
    }

    // 若“該key”對應的鍵值對不存在,則將“key-value”新增到table中
    modCount++;
    addEntry(hash, key, value, i);
    return null;
}

若要新增到HashMap中的鍵值對對應的key已經存在HashMap中,則找到該鍵值對;然後新的value取代舊的value,並退出!
若要新增到HashMap中的鍵值對對應的key不在HashMap中,則將其新增到該雜湊值對應的連結串列中,並呼叫addEntry()

  • addEntry()方法
void addEntry(int hash, K key, V value, int bucketIndex) {
    // 儲存“bucketIndex”位置的值到“e”中
    Entry<K,V> e = table[bucketIndex];
    // 設定“bucketIndex”位置的元素為“新Entry”,
    // 設定“e”為“新Entry的下一個節點”
    table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
    // 若HashMap的實際大小 不小於 “閾值”,則調整HashMap的大小
    if (size++ >= threshold)
        resize(2 * table.length);
}

addEntry() 的作用是新增Entry。將“key-value”插入指定位置,bucketIndex是位置索引。 

  • putAll()方法

將m中的元素全部存放在HashMap物件中,程式碼如下

public void putAll(Map<? extends K, ? extends V> m) {
    // 有效性判斷
    int numKeysToBeAdded = m.size();
    if (numKeysToBeAdded == 0)
        return;

    // 計算容量是否足夠,
    // 若“當前實際容量 < 需要的容量”,則將容量x2。
    if (numKeysToBeAdded > threshold) {
        int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1);
        if (targetCapacity > MAXIMUM_CAPACITY)
            targetCapacity = MAXIMUM_CAPACITY;
        int newCapacity = table.length;
        while (newCapacity < targetCapacity)
            newCapacity <<= 1;
        if (newCapacity > table.length)
            resize(newCapacity);
    }

    // 通過迭代器,將“m”中的元素逐個新增到HashMap中。
    for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i = m.entrySet().iterator(); i.hasNext(); ) {
        Map.Entry<? extends K, ? extends V> e = i.next();
        put(e.getKey(), e.getValue());
    }
}
  • remove()方法

刪除鍵值為key的元素

public V remove(Object key) {
    Entry<K,V> e = removeEntryForKey(key);
    return (e == null ? null : e.value);
}


// 刪除“鍵為key”的元素
final Entry<K,V> removeEntryForKey(Object key) {
    // 獲取雜湊值。若key為null,則雜湊值為0;否則呼叫hash()進行計算
    int hash = (key == null) ? 0 : hash(key.hashCode());
    int i = indexFor(hash, table.length);
    Entry<K,V> prev = table[i];
    Entry<K,V> e = prev;

    // 刪除連結串列中“鍵為key”的元素
    // 本質是“刪除單向連結串列中的節點”
    while (e != null) {
        Entry<K,V> next = e.next;
        Object k;
        if (e.hash == hash &&
            ((k = e.key) == key || (key != null && key.equals(k)))) {
            modCount++;
            size--;
            if (prev == e)
                table[i] = next;
            else
                prev.next = next;
            e.recordRemoval(this);
            return e;
        }
        prev = e;
        e = next;
    }

    return e;
}
  • HashMap實現Cloneable介面

作用很簡單,就是克隆一個HashMap物件並且返回

// 克隆一個HashMap,並返回Object物件
public Object clone() {
    HashMap<K,V> result = null;
    try {
        result = (HashMap<K,V>)super.clone();
    } catch (CloneNotSupportedException e) {
        // assert false;
    }
    result.table = new Entry[table.length];
    result.entrySet = null;
    result.modCount = 0;
    result.size = 0;
    result.init();
    // 呼叫putAllForCreate()將全部元素新增到HashMap中
    result.putAllForCreate(this);

    return result;
}
  • HashMap實現Serializable介面

HashMap實現java.io.Serializable,分別實現了序列讀取、寫入功能。
序列寫入函式是writeObject(),它的作用是將HashMap的“總的容量,實際容量,所有的Entry”都寫入到輸出流中。
而序列讀取函式是readObject(),它的作用是將HashMap的“總的容量,實際容量,所有的Entry”依次讀出

// java.io.Serializable的寫入函式
// 將HashMap的“總的容量,實際容量,所有的Entry”都寫入到輸出流中
private void writeObject(java.io.ObjectOutputStream s)
    throws IOException
{
    Iterator<Map.Entry<K,V>> i =
        (size > 0) ? entrySet0().iterator() : null;

    // Write out the threshold, loadfactor, and any hidden stuff
    s.defaultWriteObject();

    // Write out number of buckets
    s.writeInt(table.length);

    // Write out size (number of Mappings)
    s.writeInt(size);

    // Write out keys and values (alternating)
    if (i != null) {
        while (i.hasNext()) {
        Map.Entry<K,V> e = i.next();
        s.writeObject(e.getKey());
        s.writeObject(e.getValue());
        }
    }
}

// java.io.Serializable的讀取函式:根據寫入方式讀出
// 將HashMap的“總的容量,實際容量,所有的Entry”依次讀出
private void readObject(java.io.ObjectInputStream s)
     throws IOException, ClassNotFoundException
{
    // Read in the threshold, loadfactor, and any hidden stuff
    s.defaultReadObject();

    // Read in number of buckets and allocate the bucket array;
    int numBuckets = s.readInt();
    table = new Entry[numBuckets];

    init();  // Give subclass a chance to do its thing.

    // Read in size (number of Mappings)
    int size = s.readInt();

    // Read the keys and values, and put the mappings in the HashMap
    for (int i=0; i<size; i++) {
        K key = (K) s.readObject();
        V value = (V) s.readObject();
        putForCreate(key, value);
    }
}

HashMap遍歷方式

  • 遍歷鍵值對

1,根據entrySet獲取到所有鍵值對,

2,通過迭代器遍歷出來

// 假設map是HashMap物件
// map中的key是String型別,value是Integer型別
Integer integ = null;
Iterator iter = map.entrySet().iterator();
while(iter.hasNext()) {
    Map.Entry entry = (Map.Entry)iter.next();
    // 獲取key
    key = (String)entry.getKey();
        // 獲取value
    integ = (Integer)entry.getValue();
}
  • 遍歷鍵

第一步:根據keySet()獲取HashMap的“鍵”的Set集合。
第二步:通過Iterator迭代器遍歷“第一步”得到的集合。

// 假設map是HashMap物件
// map中的key是String型別,value是Integer型別
String key = null;
Integer integ = null;
Iterator iter = map.keySet().iterator();
while (iter.hasNext()) {
        // 獲取key
    key = (String)iter.next();
        // 根據key,獲取value
    integ = (Integer)map.get(key);
}
  • 遍歷值

第一步:根據value()獲取HashMap的“值”的集合。
第二步:通過Iterator迭代器遍歷“第一步”得到的集合。

// 假設map是HashMap物件
// map中的key是String型別,value是Integer型別
Integer value = null;
Collection c = map.values();
Iterator iter= c.iterator();
while (iter.hasNext()) {
    value = (Integer)iter.next();
}
  • 測試程式
import java.util.Map;
import java.util.Random;
import java.util.Iterator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map.Entry;
import java.util.Collection;

/*
 * @desc 遍歷HashMap的測試程式。
 *   (01) 通過entrySet()去遍歷key、value,參考實現函式:
 *        iteratorHashMapByEntryset()
 *   (02) 通過keySet()去遍歷key、value,參考實現函式:
 *        iteratorHashMapByKeyset()
 *   (03) 通過values()去遍歷value,參考實現函式:
 *        iteratorHashMapJustValues()
 *
 * @author skywang
 */
public class HashMapIteratorTest {

    public static void main(String[] args) {
        int val = 0;
        String key = null;
        Integer value = null;
        Random r = new Random();
        HashMap map = new HashMap();

        for (int i=0; i<12; i++) {
            // 隨機獲取一個[0,100)之間的數字
            val = r.nextInt(100);
            
            key = String.valueOf(val);
            value = r.nextInt(5);
            // 新增到HashMap中
            map.put(key, value);
            System.out.println(" key:"+key+" value:"+value);
        }
        // 通過entrySet()遍歷HashMap的key-value
        iteratorHashMapByEntryset(map) ;
        
        // 通過keySet()遍歷HashMap的key-value
        iteratorHashMapByKeyset(map) ;
        
        // 單單遍歷HashMap的value
        iteratorHashMapJustValues(map);        
    }
    
    /*
     * 通過entry set遍歷HashMap
     * 效率高!
     */
    private static void iteratorHashMapByEntryset(HashMap map) {
        if (map == null)
            return ;

        System.out.println("\niterator HashMap By entryset");
        String key = null;
        Integer integ = null;
        Iterator iter = map.entrySet().iterator();
        while(iter.hasNext()) {
            Map.Entry entry = (Map.Entry)iter.next();
            
            key = (String)entry.getKey();
            integ = (Integer)entry.getValue();
            System.out.println(key+" -- "+integ.intValue());
        }
    }

    /*
     * 通過keyset來遍歷HashMap
     * 效率低!
     */
    private static void iteratorHashMapByKeyset(HashMap map) {
        if (map == null)
            return ;

        System.out.println("\niterator HashMap By keyset");
        String key = null;
        Integer integ = null;
        Iterator iter = map.keySet().iterator();
        while (iter.hasNext()) {
            key = (String)iter.next();
            integ = (Integer)map.get(key);
            System.out.println(key+" -- "+integ.intValue());
        }
    }
    

    /*
     * 遍歷HashMap的values
     */
    private static void iteratorHashMapJustValues(HashMap map) {
        if (map == null)
            return ;
        
        Collection c = map.values();
        Iterator iter= c.iterator();
        while (iter.hasNext()) {
            System.out.println(iter.next());
       }
    }
}
  • import java.util.Map;
    import java.util.Random;
    import java.util.Iterator;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.Map.Entry;
    import java.util.Collection;
    
    /*
     * @desc HashMap測試程式
     *        
     * @author skywang
     */
    public class HashMapTest {
    
        public static void main(String[] args) {
            testHashMapAPIs();
        }
        
        private static void testHashMapAPIs() {
            // 初始化隨機種子
            Random r = new Random();
            // 新建HashMap
            HashMap map = new HashMap();
            // 新增操作
            map.put("one", r.nextInt(10));
            map.put("two", r.nextInt(10));
            map.put("three", r.nextInt(10));
    
            // 打印出map
            System.out.println("map:"+map );
    
            // 通過Iterator遍歷key-value
            Iterator iter = map.entrySet().iterator();
            while(iter.hasNext()) {
                Map.Entry entry = (Map.Entry)iter.next();
                System.out.println("next : "+ entry.getKey() +" - "+entry.getValue());
            }
    
            // HashMap的鍵值對個數        
            System.out.println("size:"+map.size());
    
            // containsKey(Object key) :是否包含鍵key
            System.out.println("contains key two : "+map.containsKey("two"));
            System.out.println("contains key five : "+map.containsKey("five"));
    
            // containsValue(Object value) :是否包含值value
            System.out.println("contains value 0 : "+map.containsValue(new Integer(0)));
    
            // remove(Object key) : 刪除鍵key對應的鍵值對
            map.remove("three");
    
            System.out.println("map:"+map );
    
            // clear() : 清空HashMap
            map.clear();
    
            // isEmpty() : HashMap是否為空
            System.out.println((map.isEmpty()?"map is empty":"map is not empty") );
        }
    }
    map:{two=7, one=9, three=6}
    next : two - 7
    next : one - 9
    next : three - 6
    size:3
    contains key two : true
    contains key five : false
    contains value 0 : false
    map:{two=7, one=9}
    map is empty

原文:https://www.cnblogs.com/skywang12345/p/3310835.html