1. 程式人生 > 其它 >EighteenDay-java Map及其實現類HashMap、Hashtable

EighteenDay-java Map及其實現類HashMap、Hashtable

1、Map<k,v>介面的常用方法

  V put(K key, V value) 新增鍵值對

  void clear() 清除所有鍵值對

  boolean containsKey(Object key) 是否包含指定鍵 是就返回true

  boolean containsValue(Object value) 是否包含指定值 是就返回true

  V get(Object key) 以鍵找值 返回值

  boolean isEmpty() 此地圖是否包含鍵值對 不包含返回true

  Set<K> keySet() 獲取所有的鍵 以set集合形式返回

  V remove(Object key) 以鍵刪除鍵值對

  int size() 此地圖中含有多少個鍵值對

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

    Map: 1:zhangsan 2:lisi 3:wangwu

    Set: 1=zhangsan 2=lisi 3=wangwu [它們的型別是Map.Entry<k,v>]

public static void main(String[] args) {
//建立Map集合物件
Map<Integer,String> map=new HashMap<>();
//新增鍵值對
map.put(1,"zhangsan");
map.put(2,"wangwu");
map.put(3,"lisi");
map.put(4,"liuliu");
//Map中鍵值對的個數
System.out.println(map.size());//4
//以鍵找值
System.out.println(map.get(1));//zhangsan
//包含鍵
System.out.println(map.containsKey(3));//true
//包含值
System.out.println(map.containsValue("zhangsan"));//true
//刪除鍵值對
String v=map.remove(2);
System.out.println(v);//wangwu
//是否為空
System.out.println(map.isEmpty());//false
//返回所有鍵
Set<Integer> ints = map.keySet();
for (Integer anInt : ints) {
System.out.print(anInt+" ");//1 3 4
}

2、有關Map取鍵值對

鍵值對的第一種獲取方式:先獲取所有的鍵,在獲取值

第二種方式 把鍵值對一起取出來(效率較高)

public static void main(String[] args) {
Map<Integer,String> map=new HashMap<>();
map.put(1,"wo");
map.put(2,"hao");
map.put(3,"ni");
//鍵值對的第一種獲取方式:先獲取所有的鍵,在獲取值
//獲取所有鍵
Set<Integer> keys = map.keySet();
/* //迭代器
Iterator<Integer> k= keys.iterator();
//迭代
while(k.hasNext()){
Integer k1 = k.next();
System.out.println(k1+":"+map.get(k1));
}
*/
//foreach
for (Integer key : keys) {
System.out.print(key+":"+map.get(key)+" ");//1:wo 2:hao 3:ni

}
System.out.println();
//第二種方式 把鍵值對一起取出來

Set<Map.Entry<Integer, String>> set = map.entrySet();
for (Map.Entry<Integer, String> node: set) {
System.out.print(node.getKey()+":"+node.getValue()+" ");//1:wo 2:hao 3:ni
}

}

3、HashMap

  1>、HsahMap集合底層是雜湊表/散列表的資料結構

  2>、雜湊表是一個數組和單向列表的結合體

    陣列在查詢方面效率很高,連結串列在增刪方面效率很高

  3>、HsahMap底層原始碼

//HashMap底層實際上是一個一維陣列
Node<k,v>[] table;
//靜態內部類HashMap.Node
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;//雜湊值,是key的hashCode()方法執行結果。hash值通過演算法函式,可以轉換成地址
final K key;//儲存到Map集合中的key
V value;//儲存到Map集合中的Value
Node<K,V> next;//下一個節點的記憶體地址
}

雜湊表/散列表:一維陣列,這個陣列中的每一個元素都是一個單向連結串列

4、HashMap集合的存取原理

Map中的put(k,v)方法原理:

接收k,v後,封裝到Node<k,v>物件中,呼叫k的hashCode()方法,得到K的雜湊值,通過雜湊函式與演算法生成陣列下標值,找到對應的陣列下標位置,若為空,則直接把鍵值對放進去,若不為空,則一一比較在此陣列下標 位置上的連結串列的k值,使用equals,返回true則把v值用新的覆蓋,返回false,則把此鍵值對放在連結串列的末尾

Map中的get(k)方法原理:

接收到k值後 底層呼叫hashCode方法,得到k的雜湊值後通過雜湊函式和演算法生成陣列下標,通過陣列下標快速定位到連結串列在陣列中的位置,若此位置為null則返回null,若不為空,拿k與單鏈表一一比較通過equals ,返回true則拿出k對應的v值,返回false 則返回null。

綜上知,若要自定義引用型別,使用集合,一定要重寫equals和hashCode方法。

如果hashCode返回的值只有一個,則此雜湊表為純連結串列,屬於不均勻散列表

分佈均勻散列表:有100個元素,陣列空間為10,則每個空間有10個;

如果hashCode返回值每次都返回不一樣的值,則雜湊表為純陣列,屬於不均勻散列表

重點:HashMap集合的預設初始化容量是16,預設因子是0.75 預設因子:當HashMap底層陣列的容量達到75%的時候,陣列開始擴 容,HashMap 集合的初始化容量必須是2的倍數,因為為了達到雜湊 均勻,調高HashMap集合的存取效率

如圖所示

(圖為B站老師所畫)

HashMap集合的key特點

無序不可重複:

無序:因為不一定掛到那個連結串列上

不可重複:equals保證了key不會重複

*JDK8之後在雜湊表中當單向連結串列超過8個,則資料結構會變為紅黑樹結構,當紅黑樹節點小於6時又變回連結串列

5、Hashtable

Hashtable可以為空嗎?

  Hashtable的鍵與值都不可以為null

  HashMap的鍵與值可以為null

Hashtable方法都帶有synchronized:執行緒安全的。執行緒安全有其他方案,這個Hashtable對執行緒的處理效率較低,運用較少了。

底層都是雜湊表,初始化容量是11,預設載入容量0.75f,擴容是原容量乘以2加1.

public static void main(String[] args) {
Map map=new Hashtable();
map.put(null,100);//NullPointerException異常
System.out.println(map.size());
}

6、Properties

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

   Properties是Map的一個集合,繼承Hashtable

  Properties的key與value都是String型別的

   Properties被稱為屬性類物件

//存
properties.setProperty("url","jdbc:mysql://localhost:3306/product");
//取
String url = properties.getProperty("url");
System.out.println(url);//jdbc:mysql://localhost:3306/product

7、TreeSet

  1>、TreeSet集合無序不重複,但可以按大小排序,底層是TreeMap

  2>、TreeMap的底層是二叉樹

  3>、TreeSet儲存資料相當於在TreeMap的key裡儲存

  4>對於自定義型別來說,可以排序嗎?

  無法排序,因為沒有指定排序規則 會出現ClassCastException異常:class EighteenDay.student cannot be cast to class java.lang.Comparable

  在底層程式碼中,HashMap的put方法會進行鍵的比較(compareTo()方法),鍵值在比較前會強制轉換成Comparable比較器型別,而student為自定義型別 沒有實現比較器介面,故無  法轉型,報錯。

  總結:在使用TreeSet/TreeMap集合儲存自定義型別資料時,自定義類一定要繼承Java.lang.Comparable,重寫compareTo方法進行排序規則的制定

public static void main(String[] args) {
  student st=new student(13);
  student st2=new student(12);
  TreeSet<student> ts=new TreeSet<>();
  ts.add(st);
  ts.add(st2);
  System.out.println(ts.size());
  for (student t : ts) {
    System.out.println(t);
  }
}

class student implements Comparable<student>{
  int age;

  public student(int age) {
    this.age = age;
  }
//重寫compareTo 制定排序規則
  @Override
  public int compareTo(student o) {
    return this.age-o.age;//這個是降序 o.age-this.age 就順序相反了(升序)
  /*底層程式碼以二叉樹的形式排序,我們需要在這裡重寫compareTo返回三種情況的某一種,負數,0,正數
  cmp = k.compareTo(t.key);
  if (cmp < 0)
  t = t.left;
  else if (cmp > 0)
  t = t.right;
  else
  return t.setValue(value);
  */
  }
  //重寫toString方法
  @Override
  public String toString() {
    return "age=" + age;
  }
}