Java HashMap集合

HashMap 是一個(gè)散列表,它存儲(chǔ)的內(nèi)容是鍵值對(duì)(key-value)映射。
HashMap 繼承于AbstractMap,實(shí)現(xiàn)了Map、Cloneable、java.io.Serializable接口。
HashMap 的實(shí)現(xiàn)不是同步的,這意味著它不是線程安全的。它的key、value都可以為null。此外,HashMap中的映射不是有序的。

HashMap 的實(shí)例有兩個(gè)參數(shù)影響其性能:“初始容量” 和 “加載因子”。容量 是哈希表中桶的數(shù)量,初始容量 只是哈希表在創(chuàng)建時(shí)的容量。加載因子 是哈希表在其容量自動(dòng)增加之前可以達(dá)到多滿的一種尺度。當(dāng)哈希表中的條目數(shù)超出了加載因子與當(dāng)前容量的乘積時(shí),則要對(duì)該哈希表進(jìn)行 rehash 操作(即重建內(nèi)部數(shù)據(jù)結(jié)構(gòu)),從而哈希表將具有大約兩倍的桶數(shù)。
通常,默認(rèn)加載因子是 0.75, 這是在時(shí)間和空間成本上尋求一種折衷。加載因子過(guò)高雖然減少了空間開(kāi)銷,但同時(shí)也增加了查詢成本(在大多數(shù) HashMap 類的操作中,包括 get 和 put 操作,都反映了這一點(diǎn))。在設(shè)置初始容量時(shí)應(yīng)該考慮到映射中所需的條目數(shù)及其加載因子,以便最大限度地減少 rehash 操作次數(shù)。如果初始容量大于最大條目數(shù)除以加載因子,則不會(huì)發(fā)生 rehash 操作。

構(gòu)造方法
| 方法 | 描述 |
| HashMap() | 默認(rèn)構(gòu)造方法 |
| HashMap(int capacity) | 構(gòu)造一個(gè)指定初始容量和默認(rèn)加載因子(0.75)的空HashMap |
| HashMap(int capacity, float loadFactor) | 構(gòu)造一個(gè)指定容量到小和加載因子的空HashMap |
| HashMap(Map<? extends K, ? extends V> map) | 構(gòu)造一個(gè)映射關(guān)系與指定Map相同的新HashMap |

| 常用方法 | 描述 |
| put(K key, V value) | 通過(guò)此方法將鍵值對(duì)添加到HashMap中 |
| putAll(Map<? extends K, ? extends V> map) | 將另一個(gè)map集合復(fù)制到此集合中 |

import java.util.HashMap;
import java.util.Set;
import java.util.Iterator;
import java.util.Collection;
import java.util.Map.Entry;

public class HashMapExercise {
    public static void main(String[] args) {
 HashMap<String, Integer> map = new HashMap<>();
        // 添加方法
        map.put("小紅", 18);
        map.put("小明", 30);
        map.put("小輝", 20);
        map.put("小李", 18);
        System.out.println(map);  // {小輝=18, 小明=18, 小李=18, 小紅=18}
        //判斷鍵是否存在
        boolean flg = map.containsKey("小明");
        System.out.println(flg); // true
        // 判斷值是否存在
        flg = map.containsValue(18);
        System.out.println(flg); // true
        // 判斷集合是否為空
        flg = map.isEmpty();
        System.out.println(flg); // false
        // 根據(jù)鍵獲取值
        Integer i = map.get("小李");
        System.out.println(i); // 18
        // 獲取集合中元素的個(gè)數(shù)
        int size = map.size();
        System.out.println(size); // 4


        // Map集合的四種遍歷方式
        // 遍歷結(jié)果
        // Key:小輝,Value:20
        // Key:小明,Value:30
        // Key:小李,Value:18
        // Key:小紅,Value:18
        // 第一種: 通過(guò)keySet()方法獲取到所有鍵的Set集合
        Set<String> keySet = map.keySet(); // map集合使用keySet()方法返回的是所有的key的值
        for (String str : keySet) {
            Integer in = map.get(str);
            System.out.println("Key:"+str+",Value:"+in);
        }

        // 第二種: 通過(guò)entrySet()方法獲取所有的鍵值對(duì)的Set集合 Entry<String, Integer>
        Set<HashMap.Entry<String, Integer>> entrySet = map.entrySet(); // map集合使用entrySet()方法返回的是所有的鍵值對(duì)
        // 通過(guò)這種方式獲得的所有鍵值對(duì)還需要使用迭代器進(jìn)行遍歷
        Iterator<Map.Entry<String, Integer>> iterator = entrySet.iterator();
        while (iterator.hasNext()) {
            HashMap.Entry<String, Integer> entry = iterator.next();
            System.out.println("Key:"+entry.getKey()+",Value:"+entry.getValue());
        }

        // 第三種: 使用foreach循環(huán)進(jìn)行遍歷;當(dāng)容量較大時(shí),推薦.
        for (HashMap.Entry<String , Integer> entry: map.entrySet()) {
            // Map.Entry<String, Integer> 映射項(xiàng)(鍵-值對(duì))
            // 這種方法也可用于 keySet()和values()
            System.out.println("Key:"+entry.getKey()+",Value:"+entry.getValue());
        }


        // 第四種: 通過(guò)values()方法獲取所有值的Collection集合
        // 遍歷結(jié)果
        // value:20
        // value:30
        // value:18
        // value:18
        Collection<Integer> values = map.values();
        Iterator<Integer> it = values.iterator();
        while(it.hasNext()) {
            Integer value = it.next();
            System.out.println("value:"+value); // 我們不能通過(guò)值去進(jìn)行鍵的查找
        }
    }
}

HashMap集合就是Map接口實(shí)現(xiàn)的類,Map能實(shí)現(xiàn)的功能,HashMap基本都能實(shí)現(xiàn).

HashMap和Hashtable的區(qū)別
它們的主要的區(qū)別有:線程安全性,同步(synchronization),以及速度。

  • HashMap幾乎可以等價(jià)于Hashtable,除了HashMap是非synchronized的,并可以接受null(HashMap可以接受為null的鍵值(key)和值(value),而Hashtable則不行)。
  • HashMap是非synchronized,而Hashtable是synchronized,這意味著Hashtable是線程安全的,多個(gè)線程可以共享一個(gè)Hashtable;而如果沒(méi)有正確的同步的話,多個(gè)線程是不能共享HashMap的。Java 5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的擴(kuò)展性更好。
  • 另一個(gè)區(qū)別是HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。所以當(dāng)有其它線程改變了HashMap的結(jié)構(gòu)(增加或者移除元素),將會(huì)拋出ConcurrentModificationException,但迭代器本身的remove()方法移除元素則不會(huì)拋出ConcurrentModificationException異常。但這并不是一個(gè)一定發(fā)生的行為,要看JVM。這條同樣也是Enumeration和Iterator的區(qū)別。
  • 由于Hashtable是線程安全的也是synchronized,所以在單線程環(huán)境下它比HashMap要慢。如果你不需要同步,只需要單一線程,那么使用HashMap性能要好過(guò)Hashtable。HashMap不能保證隨著時(shí)間的推移Map中的元素次序是不變的。

要注意的一些重要術(shù)語(yǔ):

  1. sychronized意味著在一次僅有一個(gè)線程能夠更改Hashtable。就是說(shuō)任何線程要更新Hashtable時(shí)要首先獲得同步鎖,其它線程要等到同步鎖被釋放之后才能再次獲得同步鎖更新Hashtable。

  2. Fail-safe和iterator迭代器相關(guān)。如果某個(gè)集合對(duì)象創(chuàng)建了Iterator或者ListIterator,然后其它的線程試圖“結(jié)構(gòu)上”更改集合對(duì)象,將會(huì)拋出ConcurrentModificationException異常。但其它線程可以通過(guò)set()方法更改集合對(duì)象是允許的,因?yàn)檫@并沒(méi)有從“結(jié)構(gòu)上”更改集合。但是假如已經(jīng)從結(jié)構(gòu)上進(jìn)行了更改,再調(diào)用set()方法,將會(huì)拋出IllegalArgumentException異常。

  3. 結(jié)構(gòu)上的更改指的是刪除或者插入一個(gè)元素,這樣會(huì)影響到map的結(jié)構(gòu)。

我們能否讓HashMap同步?
HashMap可以通過(guò)下面的語(yǔ)句進(jìn)行同步:
Map m = Collections.synchronizeMap(hashMap);

結(jié)論
Hashtable和HashMap有幾個(gè)主要的不同:線程安全以及速度。僅在你需要完全的線程安全的時(shí)候使用Hashtable,而如果你使用Java 5或以上的話,請(qǐng)使用ConcurrentHashMap吧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 在一個(gè)方法內(nèi)部定義的變量都存儲(chǔ)在棧中,當(dāng)這個(gè)函數(shù)運(yùn)行結(jié)束后,其對(duì)應(yīng)的棧就會(huì)被回收,此時(shí),在其方法體中定義的變量將不...
    Y了個(gè)J閱讀 4,575評(píng)論 1 14
  • Java集合類可用于存儲(chǔ)數(shù)量不等的對(duì)象,并可以實(shí)現(xiàn)常用的數(shù)據(jù)結(jié)構(gòu)如棧,隊(duì)列等,Java集合還可以用于保存具有映射關(guān)...
    小徐andorid閱讀 2,091評(píng)論 0 13
  • Java8張圖 11、字符串不變性 12、equals()方法、hashCode()方法的區(qū)別 13、...
    Miley_MOJIE閱讀 3,899評(píng)論 0 11
  • 我是一顆智齒,有著很可愛(ài)的名字。呵呵!討厭!人家叫多多。 可能很多牙的命運(yùn)從一生長(zhǎng)就開(kāi)始注定。 ...
    美西xyy閱讀 222評(píng)論 1 0
  • 一夜夢(mèng)境,鬧鐘響時(shí)翻身看小妞還在熟睡,自個(gè)也困隨手按停。5分鐘后岳云鵬《五環(huán)之歌》再次響起,壞壞的把鬧鐘放到小妞耳...
    向向向上閱讀 219評(píng)論 0 0

友情鏈接更多精彩內(nèi)容