1. 程式人生 > 實用技巧 >十二、集合:Map

十二、集合:Map

1.Map集合繼承結構圖:【UML】

圖片來源網路,如有侵權私信刪除。

2.Map介面:

2.1、Map與Collection沒有繼承關係。

2.2、Map集合以key和 value的方式儲存資料型別:鍵值對

  key和value都是引用資料型別。儲存的都是物件的記憶體地址。

  key起到主導作用,value是key的附屬品。

2.3、常用方法:

  V put(K key, V value); //向Map集合新增鍵值對

  V get(Object key); //通過key獲取value

  void clear(); //清空Map集合

  boolean containsKey(Object key); //判斷Map集合中包含某個key

  boolean containsValue(Object value); //判斷Map集合中包含某個value

  boolean isEmpty(); //判斷Map集合中元素個數是否為0

  Set<K> keySet(); //獲取Map集合所有的key(所有的鍵是一個set集合)

  V remove(Object key); //通過key刪除鍵值對

  int size(); //獲取Map集合中鍵值對個數

  Collection<V> values(); //獲取Map集合中所有的value,返回一個Collection

  Set<Map.Entry<K, V>> entrySet(); //將Map集合轉換成Set集合

Map集合通過entrySet()方法轉換成這個Set集合,Set集合中元素型別是 【Map.Entry<K, V>】

  Map.Entry與String一樣,是一種型別的名字。只不過,Map.Entry是靜態內部類,是Map中的靜態內部類。

View Code
2.5、Map集合的遍歷:

  第一種:獲取所有的key,通過遍歷key,來遍歷value

  第二種:Set<Map.Entry<k,v>> entrySet();

   獲取key和value都是直接從node物件中獲取屬性值(適合大資料量)

View Code

3.HashMap集合:

3.1、1.HashMap集合底層是雜湊表/散列表的資料結構。

3.2、雜湊表的資料結構: 

  雜湊表是一個數組和單向連結串列的結合體。

  陣列:在查詢方面效率很高,隨機增刪效率很低。

  連結串列:在隨機增刪方面效率較高,在查詢方面效率很低。

  雜湊表將以上兩種資料結構融合在一起,發揮各自的有點。

3.3、HashMap集合底層的原始碼: 

    public class HashMap{
    //HashMap底層是一維陣列
    transient Node<k,v>[] table;


    //靜態內部類
    static class Node<K,V> implements Map.Entry<K,V> {
      final int hash;//雜湊值(雜湊值是key的hashCode()方法執行的結果)
      //hash值通過雜湊函式/演算法,可以轉換儲存陣列的下標。
      final K key;
      V value;
      Node<K,V> next;

    }
  }
View Code

雜湊表/散列表:一維陣列,這個陣列中每一個元素是一個單項鍊表(陣列和連結串列的結合體)。

3.4、以下方法的實現原理:

  public V put(K key, V value);

原理:

第一步:先將k,v分裝到Node物件當中。
第二步:底層呼叫k的hashCode()方法得出hash值然後通過雜湊函式/演算法,將hash值轉換成陣列的下標,下標位置上如果沒有任何元素,就把Node新增到那個位置上。如果下標對應的位置上有連結串列,此時會拿著 k 和連結串列上的每個節點的k進行equals,如果所有的equals方法返回的都是false,那麼這個節點將會被新增到連結串列的末尾,如果其中有一個equals返回了true,這個節點的value將會被覆蓋。

  public V get(Object key);

原理:

  先呼叫k的hashCode()方法得出雜湊值,通過雜湊演算法轉換成陣列下標,通過陣列下標快速定位到某個位置上,如果這個位置什麼都沒有返回null。如果這個位置有單向連結串列,則會拿著引數k和單向連結串列上的每一個節點中的k進行equals,如果所有equal方法返回false,那麼get方法返回null。如果其中一個equals方法返回true,那這個節點的value就是要找的value,get方法最終返回要找的value。

重點:

 HashMap集合的key,會先後呼叫兩個方法,一個方法是hashCode(),一個是equals(),這兩個方法都需要重寫。

雜湊表的資料結構:

圖片來源網路,如有侵權私信刪除。

3.5、為什麼雜湊表的隨機增刪,以及查詢效率都很高?

  增刪是在連結串列上完成的。查詢也不需要都掃描,只需要部分掃描。

3.6、HashMap集合key部分特點:

  無序不可重複。

為什麼無序?因為不一定掛在哪個單向連結串列上。

不可重複怎麼保證?equals方法確保HashMap集合的key不可重複。k重複則覆蓋value。

放在HashMap集合key部分的元素其實就是放在HashSet集合中了。

所以HashSet集合中的元素也需要同時重寫hashCode() + equals() 方法。  

3.7、注意:

同一個單向連結串列上所有節點的hash相同,因為陣列下標相同。

但同一個連結串列上k和k的equals方法肯定返回的是false。

雜湊表HashMap使用不當時無法發揮性能。

  假設所有的hashCode()方法返回值固定為某個值,將會導致底層雜湊表變成純單向連結串列。

  這種情況我們稱為:雜湊分佈不均勻。

  假設所有的hashCode()方法返回值都設定為不一樣的值,將會導致底層雜湊表變成一維陣列

  沒有連結串列概念,雜湊分佈不均勻。

雜湊分佈均勻需要重寫hashCode()方法有一定的技巧。

3.8、放在HashMap集合key部分的元素,以及放在HashSet集合的元素,需要同時重寫hashCode和equals方法

3.9、HashMap集合預設初始化容量為16,預設載入因子是0.75

  這個預設載入因子是當HashMap集合底層陣列的容量達到75%的時候,陣列開始擴容。

重點:HashMap集合初始容量是2的倍數,官方推薦。

這是因為達到雜湊均勻,為了提高HashMap集合的存取效率。

3.10、擴容之後是原容量的2倍。

3.11、HashMap集合key部分允許為null。null只能有一個。

public class Test {

    public static void main(String[] args) {
        //測試HashMap集合key元素特點:無序不可重複
        //Integer是key,它的hashCode和equals方法都重寫了
        Map<Integer , String> map = new HashMap<>();
        map.put(121, "aa");
        map.put(134, "bb");
        map.put(141, "cc");
        map.put(151, "dd");
        map.put(151, "dd");
        System.out.println(map.size());//4
        //遍歷
        Set<Map.Entry<Integer,String>> set = map.entrySet();
        for(Map.Entry<Integer, String> se : set) {
            System.out.println(se.getKey()+ "=" +se.getValue() );
        }
        
        Map ma = new HashMap();
        ma.put(null, "null");
        System.out.println(ma.size());
        ma.put(null, "abc");
        System.out.println(ma.get(null));
    }

}
View Code

3.12、Map集合先呼叫hashCode(),然後可能呼叫equals();

因為連結串列中元素可能只有一個。

3.13、重寫equals()和hashCode()方法

如果一個equals方法返回true,hashCode()方法返回值必須一樣。equals方法返回true,表示兩個物件相同,在同一個單向連結串列比較,同一個單向連結串列上,雜湊值相同,故hashCode()方法返回值必須相同。

雜湊碰撞(同一連結串列雜湊值可以不同)但轉化下標相同

hashCode()方法和equals()方法用IDE工具生成,但是兩個方法必須同時生成。

3.14、在JDK8之後,如果雜湊表中元素超過8個,單向連結串列這種資料結構會變成紅黑樹資料結構。當紅黑樹上的節點數量小於6時,會重新把紅黑樹變成單向連結串列資料結構。提高檢索效率。

class Student{
    String name;

    public Student() {
    }

    public Student(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Student other = (Student) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

    
}

public class Test {

    public static void main(String[] args) {
        Student s1 = new Student("aa");
        Student s2 = new Student("aa");
        System.out.println(s1.equals(s2));
        System.out.println(s1.hashCode());
        System.out.println(s2.hashCode());
        
        Set<Student> stu = new HashSet<Student>(); 
        stu.add(s1);
        stu.add(s2);
        System.out.println(stu.size());
    }

}
View Code

4.Properties屬性類物件的相關方法:

Properties是一個Map集合,繼承Hashtable,Properites的key和value都是String型別

Properties被稱為屬性類物件。是執行緒安全的。

public class Test {

    public static void main(String[] args) {
        //建立Properties物件
        Properties pro = new Properties();
        //
        pro.setProperty("123", "a");
        pro.setProperty("456", "b");
        pro.setProperty("789", "c");
        
        //通過key獲取value
        String s1 = pro.getProperty("123");
        String s2 = pro.getProperty("456");
        String s3 = pro.getProperty("789");
        System.out.println(s1);
        System.out.println(s2);
        System.out.println(s3);

    
    }

}
View Code

上一篇:十一、集合:Collection

下一篇:持續更新中