JAVA中集合解析篇二 HashMap解析-[Android_YangKe]

JAVA中集合解析篇二 HashMap解析

友情提示:閱讀本文大概需要5-8分鐘,下面有列表目錄,請對號入座,避免浪費您寶貴的時間

轉載請標明出處:—— [ 狂奔的蝸牛_楊柯]

  • HashMap類的介紹
  • HashMap數據結構
  • HashMap構造函數
  • HashMap遍歷方式
  • 練習demo

HashMap類的介紹

HashMap 是一個散列表,它存儲的內容是鍵值對(key-value)映射。
HashMap 繼承於AbstractMap,實現了Map、Cloneable、Serializable接口。
HashMap 的實現不是同步的,這意味着它不是線程安全的。它的key、value都可以爲null。此外,HashMap中的映射不是有序的。
HashMap 的實例有兩個參數影響其性能:“初始容量” 和 “加載因子”。容量 是哈希表中桶的數量,初始容量 只是哈希表在創建時的容量。加載因子 是哈希表在其容量自動增加之前可以達到多滿的一種尺度。當哈希表中的條目數超出了加載因子與當前容量的乘積時,則要對該哈希表進行 rehash 操作(即重建內部數據結構),從而哈希表將具有大約兩倍的桶數。
通常,默認加載因子是 0.75, 這是在時間和空間成本上尋求一種折衷。加載因子過高雖然減少了空間開銷,但同時也增加了查詢成本(在大多數 HashMap 類的操作中,包括 get 和 put 操作,都反映了這一點)。在設置初始容量時應該考慮到映射中所需的條目數及其加載因子,以便最大限度地減少 rehash 操作次數。如果初始容量大於最大條目數除以加載因子,則不會發生 rehash 操作。

HashMap數據結構

在java編程語言中,最基本的結構就是兩種,一個是數組,另外一個是模擬指針(引用),所有的數據結構都可以用這兩個基本結構來構造的,HashMap也不例外。HashMap實際上是一個“鏈表散列”的數據結構,即數組和鏈表的結合體。

這裏寫圖片描述
從上圖中可以看出,HashMap底層就是一個數組結構,數組中的每一項又是一個鏈表。當新建一個HashMap的時候,就會初始化一個數組。

: 源碼如下:

/** 
 * The table, resized as necessary. Length MUST Always be a power of two. 
 */  
transient Entry[] table;  

static class Entry<K,V> implements Map.Entry<K,V> {  
    final K key;  
    V value;  
    Entry<K,V> next;  
    final int hash;  
    ……  
} 

可以看出,Entry就是數組中的元素,每個 Map.Entry 其實就是一個key-value對,它持有一個指向下一個元素的引用,這就構成了鏈表

HashMap構造函數

HashMap提供了三個構造函數:

  HashMap():構造一個具有默認初始容量 (16) 和默認加載因子 (0.75) 的空 HashMap。
  HashMap(int initialCapacity):構造一個帶指定初始容量和默認加載因子 (0.75) 的空 HashMap。
  HashMap(int initialCapacity, float loadFactor):構造一個帶指定初始容量和加載因子的空 HashMap。

  在這裏提到了兩個參數:初始容量,加載因子。這兩個參數是影響HashMap性能的重要參數,其中容量表示哈希表中桶的數量,初始容量是創建哈希表時的容量,加載因子是哈希表在其容量自動增加之前可以達到多滿的一種尺度,它衡量的是一個散列表的空間的使用程度,負載因子越大表示散列表的裝填程度越高,反之愈小。對於使用鏈表法的散列表來說,查找一個元素的平均時間是O(1+a),因此如果負載因子越大,對空間的利用更充分,然而後果是查找效率的降低;如果負載因子太小,那麼散列表的數據將過於稀疏,對空間造成嚴重浪費。系統默認負載因子爲0.75,一般情況下我們是無需修改的。

HashMap遍歷方式

1> 遍歷HashMap的鍵
1> 根據keySet()獲取HashMap的“鍵”的Set集合。
2> 通過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);
}
2> 遍歷HashMap的值
1> 根據value()獲取HashMap的“值”的集合。
2> 通過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();
}

練習demo

import java.util.ArrayList;  
import java.util.HashMap;  
import java.util.HashSet;  
import java.util.Iterator;  
import java.util.List;  
import java.util.Map;  
import java.util.Set;  
import java.util.TreeSet;  

public class Collection {  

    /** 
     * 集合學習Demo 
     */  
    public static void main(String[] args) {  
        //  
    }  
    /** 
     * 類集:類集就是一系列的動態對象數組。 
     * 類集中最大的幾個操作接口:CollectionMapIterator 
     * 所有的類集操作的接口或類都在java.util包中。 
     * List接口:ArrayList(95%)、Vector(4%)、LinkedList(1%) 
     * Vector類和ArrayList類的區別: 
     * No.  區別點               ArrayList               Vector 
     * 1    時間      是新的類,是在JDK 1.2之後推出的 是舊的類是在JDK 1.0的時候就定義的 
     * 2    性能     性能較高,是採用了異步處理               性能較低,是採用了同步處理 
     * 3           輸出       支持Iterator、ListIterator輸出   除了支持Iterator、ListIterator輸出,還支持Enumeration輸出 
     *  
     */  
    public void demo1(){  
        List<String> all = new ArrayList<String>(); // 實例化List對象,並指定泛型類型  
        all.add("hello "); // 增加內容,此方法從Collection接口繼承而來  
        all.add(0, "VINCE ");// 增加內容,此方法是List接口單獨定義的  
        all.add("world"); // 增加內容,此方法從Collection接口繼承而來  
        System.out.println(all); // 打印all對象調用toString()方法  

    }  
    /** 
     * Set接口: 
     * Set接口也是Collection的子接口,與List接口最大的不同在於,Set接口裏面的內容是不允許重複的 
     * 此接口中有兩個常用的子類:HashSet、TreeSet 
     * HashSet屬於散列的存放類集,裏面的內容是無序存放的 
     * 使用HashSet實例化的Set接口實例,本身屬於無序的存放。 
     */  
    public void demo2(){  
        Set<String> all = new HashSet<String>(); // 實例化Set接口對象  
        all.add("A");  
        all.add("B");  
        all.add("C");  
        all.add("D");  
        all.add("E");  
        System.out.println(all);  

    }  
    public void demo3(){  
        Set<String> all = new HashSet<String>(); // 實例化Set接口對象  
        all.add("A");  
        all.add("B");  
        all.add("C");  
        all.add("D");  
        all.add("E");  
        String[] str = all.toArray(new String[] {});// 變爲指定的泛型類型數組  
        for (int x = 0; x < str.length; x++) {  
            System.out.print(str[x] + "、");  
        }  

    }  
    /** 
     * 排序的子類:TreeSet: 
     * 與HashSet不同的是,TreeSet本身屬於排序的子類 
     */  
    public void demo4(){  
        Set<String> all = new TreeSet<String>(); // 實例化Set接口對象\  
        all.add("D");  
        all.add("X");  
        all.add("A");  
        System.out.println(all);  

    }  
    /** 
     * 判斷兩個對象是否相等: 
     * 第一種判斷兩個對象的編碼是否一致,這個方法需要通過hashCode()完成,即:每個對象有唯一的編碼 
     * 還需要進一步驗證對象中的每個屬性是否相等,需要通過equals()完成。 
     * 關於TreeSet的排序實現,如果是集合中對象是自定義的或者說其他系統定義的類沒有實現 
     * Comparable接口,則不能實現TreeSet的排序,會報類型轉換(轉向Comparable接口)錯誤。 
     * 換句話說要添加到TreeSet集合中的對象的類型必須實現了Comparable接口. 
     */  

    /** 
     * 集合輸出: 
     * 只要是碰到了集合,則輸出的時候想都不想就使用Iterator進行輸出。 
     * Iterator 
     */  
    public void demo5(){  
        List<String> all = new ArrayList<String>();  
        all.add("A");  
        all.add("B");  
        all.add("C");  
        all.add("D");  
        all.add("E");  
        Iterator<String> iter = all.iterator();  
        while (iter.hasNext()) {// 判斷是否有下一個元素  
            String str = iter.next(); // 取出當前元素  
            System.out.print(str + "、");  
        }  

    }  
    /** 
     * Map接口: 
     * Map本身是一個接口,所以一般會使用以下的幾個子類:HashMap、TreeMap、Hashtable 
     * Map接口在開發中最基本的操作過程,根據指定的key找到內容,如果沒有找到,則返回null,找到了則返回具體的內容。 
     * HashMap本身是屬於無序存放的。 
     * Hashtable中是不能向集合中插入null值 
     * HashMap與Hashtable的區別: 
     * No.  區別點       HashMap                    Hastable 
     * 1    推出時間    JDK 1.2之後推出的,新的操作類       JDK 1.0時推出的,舊的操作類 
     * 2    性能  異步處理,性能較高                                                 同步處理,性能較低 
     * 3    null    允許設置爲null                                                 不允許設置,否則將出現空指向異常 
     */  
    public void demo6(){  
        Map<Integer, String> map = new HashMap<Integer, String>();  
        map.put(1, "張三A");  
        map.put(1, "張三B"); // 新的內容替換掉舊的內容  
        map.put(2, "李四");  
        map.put(3, "王五");  
        String val = map.get(6);  
        System.out.println(val);  

    }  
    public void demo7(){  
        Map<Integer, String> map = new HashMap<Integer, String>();  
        map.put(1, "張三A");  
        map.put(2, "李四");  
        map.put(3, "王五");  
        Set<Integer> set = map.keySet(); // 得到全部的key  
        List<String> value = (List<String>) map.values(); // 得到全部的value  
        Iterator<Integer> iter1 = set.iterator();  
        Iterator<String> iter2 = value.iterator();  
        System.out.print("全部的key:");  
        while (iter1.hasNext()) {  
            System.out.print(iter1.next() + "、");  
        }  
        System.out.print("\n全部的value:");  
        while (iter2.hasNext()) {  
            System.out.print(iter2.next() + "、");  
        }  
    }  

    //Map集合中每一個元素都是Map.Entry的實例,只有通過Map.Entry才能進行key和value的分離操作。  
    public void demo8(){  
        Map<String, String> map = new HashMap<String, String>();  
        map.put("ZS", "張三");  
        map.put("LS", "李四");  
        map.put("WW", "王五");  
        map.put("ZL", "趙六");  
        map.put("SQ", "孫七");  
        Set<Map.Entry<String, String>> set = map.entrySet();// 變爲Set實例  
        Iterator<Map.Entry<String, String>> iter = set.iterator();  
        while (iter.hasNext()) {  
            Map.Entry<String, String> me = iter.next();  
            System.out.println(me.getKey() + " --> " + me.getValue());  
        }  

    }  
    //在JDK 1.5之後也可以使用foreach完成同樣的輸出,只是這樣的操作基本上不使用。  
    public void demo9(){  
        Map<String, String> map = new HashMap<String, String>();  
        map.put("ZS", "張三");  
        map.put("LS", "李四");  
        map.put("WW", "王五");  
        map.put("ZL", "趙六");  
        map.put("SQ", "孫七");  
        for (Map.Entry<String, String> me : map.entrySet()) {  
            System.out.println(me.getKey() + " --> " + me.getValue());  
        }  

    }  
    /** 
     * 當一個對象被存進HashSet集合後,就不能修改這個對象中的那些參與計算的哈希值的字段了,否則,對象被修改後的哈 
     * 希值與最初存儲進HashSet集合中時的哈希值就不同了,在這種情況下,即使在contains方法使用該對象的當前引用作爲 
     * 的參數去HashSet集合中檢索對象,也將返回找不到對象的結果,這也會導致無法從HashSet集合中刪除當前對象,從而 
     * 造成內存泄露。 
     *  
     */  

    /** 
     * foreach輸出 
     */  
    public static void demo10(){  
        String [] strs = {"a","b","c","d","e"};  
        for(String s:strs){  
            System.out.print(s+"、");  
        }  
    }  
}  

權威文檔附上 —— [ HashMap]

HashMap 暫時更新到這裏,小夥伴們若有疑問、或者建議,趕緊跟我提啊,非常感謝。 (^__^) 嘻嘻……。晚安 睡覺去

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章