目錄
前言
1.Map集合
1.1 Map集合概述和特點
1.2 Map集合的基本功能
1.3 Map集合的獲取功能
1.4 Map集合的遍歷
1.5 Map集合案例——統計字串中每個字符出現的次數
2.集合補充知識以及常見面試題
2.1 Java集合框架圖
2.2 各集合間的對比
2.2.1 Arraylist 與 LinkedList 異同
2.2.2 ArrayList 與 Vector 區別
2.2.3 HashMap 和 Hashtable 的區別
2.3 集合框架底層資料結構總結
前言
前兩期博客中我們一起去拜訪了Java集合世界中的List集合和Set集合,今天我們一起去到Java集合世界的最后一站:Map集合,前面所說的List和Set集合都屬于單列集合,只能存盤一列資料;而Map集合是雙列集合,它將資料以鍵值對形式存盤,所以在形式上可存盤兩列資料,

1.Map集合
1.1 Map集合概述和特點
Map集合是雙列集合,它將資料以鍵值對形式存盤,所以在形式上可存盤兩列資料,Map是一個集合介面,不能直接創建物件,必須通過它的具體實作類(HashMap、TreeMap等)來創建Map物件,
interface Map<K,V> K:鍵的型別;V:值的型別
Map集合的特點
-
鍵值對映射關系
-
一個鍵對應一個值
-
鍵不能重復,值可以重復
-
元素存取無序
1.2 Map集合的基本功能
△ 方法介紹
| 方法名 | 說明 |
|---|---|
| V put(K key,V value) | 添加元素 |
| V remove(Object key) | 根據鍵洗掉鍵值對元素 |
| void clear() | 移除所有的鍵值對元素 |
| boolean containsKey(Object key) | 判斷集合是否包含指定的鍵 |
| boolean containsValue(Object value) | 判斷集合是否包含指定的值 |
| boolean isEmpty() | 判斷集合是否為空 |
| int size() | 集合的長度,也就是集合中鍵值對的個數 |
△ 示例代碼
public class MapDemo02 {
public static void main(String[] args) {
//創建集合物件
Map<String,String> map = new HashMap<String,String>();
//V put(K key,V value):添加元素
map.put("張無忌","趙敏");
map.put("郭靖","黃蓉");
map.put("楊過","小龍女");
//V remove(Object key):根據鍵洗掉鍵值對元素
// System.out.println(map.remove("郭靖"));
// System.out.println(map.remove("郭襄"));
//void clear():移除所有的鍵值對元素
// map.clear();
//boolean containsKey(Object key):判斷集合是否包含指定的鍵
// System.out.println(map.containsKey("郭靖"));
// System.out.println(map.containsKey("郭襄"));
//boolean isEmpty():判斷集合是否為空
// System.out.println(map.isEmpty());
//int size():集合的長度,也就是集合中鍵值對的個數
System.out.println(map.size());
//輸出集合物件
System.out.println(map);
}
}
1.3 Map集合的獲取功能
△ 方法介紹
| 方法名 | 說明 |
|---|---|
| V get(Object key) | 根據鍵獲取值 |
| Set<K> keySet() | 獲取所有鍵的集合 |
| Collection<V> values() | 獲取所有值的集合 |
| Set<Map.Entry<K,V>> entrySet() | 獲取所有鍵值對物件的集合 |
△ 示例代碼
public class MapDemo03 {
public static void main(String[] args) {
//創建集合物件
Map<String, String> map = new HashMap<String, String>();
//添加元素
map.put("張無忌", "趙敏");
map.put("郭靖", "黃蓉");
map.put("楊過", "小龍女");
//V get(Object key):根據鍵獲取值
// System.out.println(map.get("張無忌"));
// System.out.println(map.get("張三豐"));
//Set<K> keySet():獲取所有鍵的集合
// Set<String> keySet = map.keySet();
// for(String key : keySet) {
// System.out.println(key);
// }
//Collection<V> values():獲取所有值的集合
Collection<String> values = map.values();
for(String value : values) {
System.out.println(value);
}
}
}
1.4 Map集合的遍歷
第一種方式
-
遍歷思路
-
我們剛才存盤的元素都是成對出現的,所以我們把Map看成是一個夫妻對的集合
-
把所有的丈夫給集中起來
-
遍歷丈夫的集合,獲取到每一個丈夫
-
根據丈夫去找對應的妻子
-
-
-
步驟分析
-
獲取所有鍵的集合,用keySet()方法實作
-
遍歷鍵的集合,獲取到每一個鍵,用增強for實作
-
根據鍵去找值,用get(Object key)方法實作
-
-
代碼實作
public class MapDemo01 {
public static void main(String[] args) {
//創建集合物件
Map<String, String> map = new HashMap<String, String>();
//添加元素
map.put("張無忌", "趙敏");
map.put("郭靖", "黃蓉");
map.put("楊過", "小龍女");
//獲取所有鍵的集合,用keySet()方法實作
Set<String> keySet = map.keySet();
//遍歷鍵的集合,獲取到每一個鍵,用增強for實作
for (String key : keySet) {
//根據鍵去找值,用get(Object key)方法實作
String value = map.get(key);
System.out.println(key + "," + value);
}
}
}
第二種方式
-
遍歷思路
-
我們剛才存盤的元素都是成對出現的,所以我們把Map看成是一個夫妻對的集合
-
獲取所有結婚證的集合
-
遍歷結婚證的集合,得到每一個結婚證
-
根據結婚證獲取丈夫和妻子
-
-
-
步驟分析
-
獲取所有鍵值對物件的集合
-
Set<Map.Entry<K,V>> entrySet():獲取所有鍵值對物件的集合
-
-
遍歷鍵值對物件的集合,得到每一個鍵值對物件
-
用增強for實作,得到每一個Map.Entry
-
-
根據鍵值對物件獲取鍵和值
-
用getKey()得到鍵
-
用getValue()得到值
-
-
-
代碼實作
public class MapDemo02 {
public static void main(String[] args) {
//創建集合物件
Map<String, String> map = new HashMap<String, String>();
//添加元素
map.put("張無忌", "趙敏");
map.put("郭靖", "黃蓉");
map.put("楊過", "小龍女");
//獲取所有鍵值對物件的集合
Set<Map.Entry<String, String>> entrySet = map.entrySet();
//遍歷鍵值對物件的集合,得到每一個鍵值對物件
for (Map.Entry<String, String> me : entrySet) {
//根據鍵值對物件獲取鍵和值
String key = me.getKey();
String value = me.getValue();
System.out.println(key + "," + value);
}
}
}
1.5 Map集合案例——統計字串中每個字符出現的次數
△ 案例需求
-
鍵盤錄入一個字串,要求統計字串中每個字串出現的次數,
-
舉例:鍵盤錄入“aababcabcdabcde” 在控制臺輸出:“a(5)b(4)c(3)d(2)e(1)”
△ 代碼實作
public class HashMapDemo {
public static void main(String[] args) {
//鍵盤錄入一個字串
Scanner sc = new Scanner(System.in);
System.out.println("請輸入一個字串:");
String line = sc.nextLine();
//創建HashMap集合,鍵是Character,值是Integer
// HashMap<Character, Integer> hm = new HashMap<Character, Integer>();
TreeMap<Character, Integer> hm = new TreeMap<Character, Integer>();
//遍歷字串,得到每一個字符
for (int i = 0; i < line.length(); i++) {
char key = line.charAt(i);
//拿得到的每一個字符作為鍵到HashMap集合中去找對應的值,看其回傳值
Integer value = hm.get(key);
if (value == null) {
//如果回傳值是null:說明該字符在HashMap集合中不存在,就把該字符作為鍵,1作為值存盤
hm.put(key,1);
} else {
//如果回傳值不是null:說明該字符在HashMap集合中存在,把該值加1,然后重新存盤該字符和對應的值
value++;
hm.put(key,value);
}
}
//遍歷HashMap集合,得到鍵和值,按照要求進行拼接
StringBuilder sb = new StringBuilder();
Set<Character> keySet = hm.keySet();
for(Character key : keySet) {
Integer value = hm.get(key);
sb.append(key).append("(").append(value).append(")");
}
String result = sb.toString();
//輸出結果
System.out.println(result);
}
}
2.集合補充知識以及常見面試題
2.1 Java集合框架圖

上面這個圖就是java整個集合體系框架圖,對于初學者來說只需要掌握我標注出來的內容就差不多了,其他的作為了解內容,
2.2 各集合間的對比
2.2.1 Arraylist 與 LinkedList 異同
- 1. 是否保證執行緒安全: ArrayList 和 LinkedList 都是不同步的,也就是不保證執行緒安全;
- 2. 底層資料結構: Arraylist 底層使用的是Object陣列;LinkedList 底層使用的是雙向回圈鏈表資料結構;
- 3. 插入和洗掉是否受元素位置的影響: ① ArrayList 采用陣列存盤,所以插入和洗掉元素的時間復雜度受元素位置的影響, 比如:執行
add(E e)方法的時候, ArrayList 會默認在將指定的元素追加到此串列的末尾,這種情況時間復雜度就是O(1),但是如果要在指定位置 i 插入和洗掉元素的話(add(int index, E element))時間復雜度就為 O(n-i),因為在進行上述操作的時候集合中第 i 和第 i 個元素之后的(n-i)個元素都要執行向后位/向前移一位的操作, ② LinkedList 采用鏈表存盤,所以插入,洗掉元素時間復雜度不受元素位置的影響,都是近似 O(1)而陣列為近似 O(n),- 4. 是否支持快速隨機訪問: LinkedList 不支持高效的隨機元素訪問,而ArrayList 實作了RandmoAccess 介面,所以有隨機訪問功能,快速隨機訪問就是通過元素的序號快速獲取元素物件(對應于
get(int index)方法),- 5. 記憶體空間占用: ArrayList的空 間浪費主要體現在在list串列的結尾會預留一定的容量空間,而LinkedList的空間花費則體現在它的每一個元素都需要消耗比ArrayList更多的空間(因為要存放直接后繼和直接前驅以及資料),
2.2.2 ArrayList 與 Vector 區別
Vector 類的所有方法都是同步的,可以由兩個執行緒安全地訪問一個 Vector 物件、但是一個執行緒訪問 Vector 的話代碼要在同步操作上耗費大量的時間,
Arraylist 不是同步的,所以在不需要保證執行緒安全時時建議使用 Arraylist,
2.2.3 HashMap 和 Hashtable 的區別
- 執行緒是否安全: HashMap 是非執行緒安全的,HashTable 是執行緒安全的;HashTable 內部的方法基本都經過
synchronized修飾,(如果你要保證執行緒安全的話就使用 ConcurrentHashMap 吧!);- 效率: 因為執行緒安全的問題,HashMap 要比 HashTable 效率高一點,另外,HashTable 基本被淘汰,不要在代碼中使用它;
- 對Null key 和Null value的支持: HashMap 中,null 可以作為鍵,這樣的鍵只有一個,可以有一個或多個鍵所對應的值為 null,,但是在 HashTable 中 put 進的鍵值只要有一個 null,直接拋出 NullPointerException,
- 初始容量大小和每次擴充容量大小的不同 : ①創建時如果不指定容量初始值,Hashtable 默認的初始大小為11,之后每次擴充,容量變為原來的2n+1,HashMap 默認的初始化大小為16,之后每次擴充,容量變為原來的2倍,②創建時如果給定了容量初始值,那么 Hashtable 會直接使用你給定的大小,而 HashMap 會將其擴充為2的冪次方大小,也就是說 HashMap 總是使用2的冪作為哈希表的大小,后面會介紹到為什么是2的冪次方,
- 底層資料結構: JDK1.8 以后的 HashMap 在解決哈希沖突時有了較大的變化,當鏈表長度大于閾值(默認為8)時,將鏈表轉化為紅黑樹,以減少搜索時間,Hashtable 沒有這樣的機制,
2.3 集合框架底層資料結構總結
Collection
1. List
- Arraylist: Object陣列
- Vector: Object陣列
- LinkedList: 雙向回圈鏈表
2. Set
- HashSet(無序,唯一): 基于 HashMap 實作的,底層采用 HashMap 來保存元素
- LinkedHashSet: LinkedHashSet 繼承與 HashSet,并且其內部是通過 LinkedHashMap 來實作的,有點類似于我們之前說的LinkedHashMap 其內部是基于 Hashmap 實作一樣,不過還是有一點點區別的,
- TreeSet(有序,唯一): 紅黑樹(自平衡的排序二叉樹,)
Map
- HashMap: JDK1.8之前HashMap由陣列+鏈表組成的,陣列是HashMap的主體,鏈表則是主要為了解決哈希沖突而存在的(“拉鏈法”解決沖突).JDK1.8以后在解決哈希沖突時有了較大的變化,當鏈表長度大于閾值(默認為8)時,將鏈表轉化為紅黑樹,以減少搜索時間
- LinkedHashMap: LinkedHashMap 繼承自 HashMap,所以它的底層仍然是基于拉鏈式散列結構即由陣列和鏈表或紅黑樹組成,另外,LinkedHashMap 在上面結構的基礎上,增加了一條雙向鏈表,使得上面的結構可以保持鍵值對的插入順序,同時通過對鏈表進行相應的操作,實作了訪問順序相關邏輯,
- HashTable: 陣列+鏈表組成的,陣列是 HashMap 的主體,鏈表則是主要為了解決哈希沖突而存在的
- TreeMap: 紅黑樹(自平衡的排序二叉樹)
Java集合世界之旅到這就結束啦!各位小哥哥、小姐姐們,點個贊呀!

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/350908.html
標籤:java
