Map接口
概述:現實生活中,我們常會看到這樣的一種集合:IP地址與主機名,身份證號與個人,系統用戶名與系統用戶對象等,這種一一對應的關係,就叫做映射。Java提供了專門的集合類用來存放這種對象關係的對象,即 java.util.Map 接口。我們通過查看 Map 接口描述,發現 Map 接口下的集合與 Collection 接口下的集合,它們存儲數據的形式不同。Collection 中的集合,元素是孤立存在的(理解爲單身),向集合中存儲元素採用一個個元素的方式存儲。Map 中的集合,元素是成對存在的(理解爲夫妻)。每個元素由鍵與值兩部分組成,通過鍵可以找對所對應的值。Collection 中的集合稱爲單列集合, Map 中的集合稱爲雙列集合。需要注意的是, Map 中的集合不能包含重複的鍵,值可以重複;每個鍵只能對應一個值。Map接口中的集合都有兩個泛型變量,在使用時,要爲兩個泛型變量賦予數據類型。兩個泛型變量的數據類型可以相同,也可以不同。
總結一下:Map集合的特點:
- Map與Collection並列存在。用於保存具有映射關係的數據:key-value
- Map 中的 key 和 value 都可以是任何引用類型的數據
- Map 中的 key 用Set來存放,不允許重複,即同一個 Map 對象所對應的類,須重寫hashCode()和equals()方法
- 常用String類作爲Map的“鍵”
- key 和 value 之間存在單向一對一關係,即通過指定的 key 總能找到 唯一的、確定的 value
- Map接口的常用實現類:HashMap、TreeMap、LinkedHashMap和 Properties。其中,HashMap是 Map 接口使用頻率最高的實現類
Map接口繼承樹
Map接口:常用方法
添加、刪除、修改操作:
- Object put(Object key,Object value):將指定key-value添加到(或修改)當前map對象中
- void putAll(Map m):將m中的所有key-value對存放到當前map中
- Object remove(Object key):移除指定key的key-value對,並返回value
- void clear():清空當前map中的所有數據
舉例:
@Test
public void test1() {
//創建集合對象
Map map = new HashMap();
//添Object put(Object key,Object value):將指定key-value添加到(或修改)當前map對象中
map.put("AA", 123);
map.put(45, 123);
map.put("BB", 56);
//key重複,會使用新的value替換map中重複的value,返回被替換的value值
map.put("AA", 87);
System.out.println(map);//{AA=87, BB=56, 45=123}
Map map1 = new HashMap();
map1.put("CC", 123);
map1.put("DD", 123);
// void putAll(Map m):將m中的所有key-value對存放到當前map中
map.putAll(map1);
System.out.println(map);//{AA=87, BB=56, CC=123, DD=123, 45=123}
// Object remove(Object key):移除指定key的key-value對,並返回value
Object value = map.remove("CC");
System.out.println(value);//123
System.out.println(map);//{AA=87, BB=56, DD=123, 45=123}
// void clear():清空當前map中的所有數據
map.clear();//與map = null操作不同
System.out.println(map.size());//0
System.out.println(map);//{}
}
元素查詢的操作:
- Object get(Object key):獲取指定key對應的value
- boolean containsKey(Object key):是否包含指定的key
- boolean containsValue(Object value):是否包含指定的value
- int size():返回map中key-value對的個數
- boolean isEmpty():判斷當前map是否爲空
- boolean equals(Object obj):判斷當前map和參數對象obj是否相等
舉例:
@Test
public void test4() {
Map map = new HashMap();
map.put("AA", 123);
map.put(45, 123);
map.put("BB", 56);
// Object get(Object key):獲取指定key對應的value
System.out.println(map.get(45));//123
//boolean containsKey(Object key):是否包含指定的key
boolean isExist = map.containsKey("BB");
System.out.println(isExist);//true
// boolean containsValue(Object value):是否包含指定的value
isExist = map.containsValue(123);
System.out.println(isExist);//true
map.clear();
//int size():返回map中key-value對的個數
System.out.println(map.size());//0
// boolean isEmpty():判斷當前map是否爲空
System.out.println(map.isEmpty());//true
//boolean equals(Object obj):判斷當前map和參數對象obj是否相等
Map map1 = new HashMap();
map1.put("AA", 123);
map1.put(45, 123);
map1.put("BB", 56);
boolean equals = map.equals(map1);
System.out.println(equals);//false
}
元視圖操作的方法:
- Set keySet():返回所有key構成的Set集合
- Collection values():返回所有value構成的Collection集合
- Set entrySet():返回所有key-value對構成的Set集合
Map實現類之一:HashMap
- HashMap是 Map 接口使用頻率最高的實現類。
- 允許使用null鍵和null值,與HashSet一樣,不保證映射的順序。
- 所有的key構成的集合是Set:無序的、不可重複的。所以,key所在的類要重寫: equals()和hashCode()
- 所有的value構成的集合是Collection:無序的、可以重複的。所以,value所在的類 要重寫:equals()
- 一個key-value構成一個entry
- 所有的entry構成的集合是Set:無序的、不可重複的
- HashMap 判斷兩個 key 相等的標準是:兩個 key 通過 equals() 方法返回 true, hashCode 值也相等。
- HashMap 判斷兩個 value相等的標準是:兩個 value 通過 equals() 方法返回 true。
HashMap的存儲結構
- JDK 7及以前版本:HashMap是數組+鏈表結構(即爲鏈地址法)
- JDK 8版本發佈以後:HashMap是數組+鏈表+紅黑樹實現
HashMap存儲自定義類型鍵值
- 當給HashMap中存放自定義對象時,如果自定義對象作爲key存在,這時要保證對象唯一,必須複寫對象的hashCode和equals方法。如果要保證map中存放的key和取出的順序一致,可以使用 java.util.LinkedHashMap 集合來存放。
Map實現類之二:LinkedHashMap
- LinkedHashMap 是 HashMap 的子類
- 在HashMap存儲結構的基礎上,使用了一對雙向鏈表來記錄添加 元素的順序
- 與LinkedHashSet類似,LinkedHashMap 可以維護 Map 的迭代 順序:迭代順序與 Key-Value 對的插入順序一致
Map實現類之三:TreeMap
- TreeMap存儲 Key-Value 對時,需要根據 key-value 對進行排序。 TreeMap 可以保證所有的 Key-Value 對處於有序狀態。
- TreeSet底層使用紅黑樹結構存儲數據
- TreeMap 的 Key 的排序:
- 自然排序:TreeMap 的所有的 Key 必須實現 Comparable 接口,而且所有 的 Key 應該是同一個類的對象,否則將會拋出 ClasssCastException
- 定製排序:創建 TreeMap 時,傳入一個 Comparator 對象,該對象負責對
- TreeMap 中的所有 key 進行排序。此時不需要 Map 的 Key 實現 Comparable 接口
- TreeMap判斷兩個key相等的標準:兩個key通過compareTo()方法或 者compare()方法返回0。
import org.junit.Test;
import java.util.*;
public class TreeMapTest {
//向TreeMap中添加key-value,要求key必須是由同一個類創建的對象
//因爲要按照key進行排序:自然排序 、定製排序
//自然排序
@Test
public void test1(){
TreeMap map = new TreeMap();
User u1 = new User("Tom",23);
User u2 = new User("Jerry",32);
User u3 = new User("Jack",20);
User u4 = new User("Rose",18);
map.put(u1,98);
map.put(u2,89);
map.put(u3,76);
map.put(u4,100);
Set entrySet = map.entrySet();
Iterator iterator1 = entrySet.iterator();
while (iterator1.hasNext()){
Object obj = iterator1.next();
Map.Entry entry = (Map.Entry) obj;
System.out.println(entry.getKey() + "---->" + entry.getValue());
}
}
//定製排序
@Test
public void test2(){
TreeMap map = new TreeMap(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof User && o2 instanceof User){
User u1 = (User)o1;
User u2 = (User)o2;
return Integer.compare(u1.getAge(),u2.getAge());
}
throw new RuntimeException("輸入的類型不匹配!");
}
});
User u1 = new User("Tom",23);
User u2 = new User("Jerry",32);
User u3 = new User("Jack",20);
User u4 = new User("Rose",18);
map.put(u1,98);
map.put(u2,89);
map.put(u3,76);
map.put(u4,100);
Set entrySet = map.entrySet();
Iterator iterator1 = entrySet.iterator();
while (iterator1.hasNext()){
Object obj = iterator1.next();
Map.Entry entry = (Map.Entry) obj;
System.out.println(entry.getKey() + "---->" + entry.getValue());
}
}
}
Map實現類之四:Hashtable
- Hashtable是個古老的 Map 實現類,JDK1.0就提供了。不同於HashMap, Hashtable是線程安全的。
- Hashtable實現原理和HashMap相同,功能相同。底層都使用哈希表結構,查詢 速度快,很多情況下可以互用。
- 與HashMap不同,Hashtable 不允許使用 null 作爲 key 和 value
- 與HashMap一樣,Hashtable 也不能保證其中 Key-Value 對的順序
- Hashtable判斷兩個key相等、兩個value相等的標準,與HashMap一致。
Map實現類之五:Properties
- Properties 類是 Hashtable 的子類,該對象用於處理屬性文件
- 由於屬性文件裏的 key、value 都是字符串類型,所以 Properties 裏的 key 和 value 都是字符串類型
- 存取數據時,建議使用setProperty(String key,String value)方法和 getProperty(String key)方法
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
public class PropertiesTest {
//Properties:常用來處理配置文件。key和value都是String類型
public static void main(String[] args) {
FileInputStream fis = null;
try {
Properties pros = new Properties();
fis = new FileInputStream("jdbc.properties");
pros.load(fis);//加載流對應的文件
String name = pros.getProperty("name");
String password = pros.getProperty("password");
System.out.println("name = " + name + ", password = " + password);
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
Ma集合遍歷的方式
Map集合遍歷鍵找值方式:即通過元素中的鍵,獲取鍵所對應的值
分析步驟:
- 獲取Map中所有的鍵,由於鍵是唯一的,所以返回一個Set集合存儲所有的鍵。方法提示: public Set<K> keySet() : 獲取Map集合中所有的鍵,存儲到Set集合中。
- 遍歷鍵的Set集合,得到每一個鍵。
- 根據鍵,獲取鍵所對應的值。方法提示: get(K key)
代碼演示:
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/*
Map集合的第一種遍歷方式:通過鍵找值的方式
Map集合中的方法:
Set<K> keySet() 返回此映射中包含的鍵的 Set 視圖。
實現步驟:
1.使用Map集合中的方法keySet(),把Map集合所有的key取出來,存儲到一個Set集合中
2.遍歷set集合,獲取Map集合中的每一個key
3.通過Map集合中的方法get(key),通過key找到value
*/
public class Demo02KeySet {
public static void main(String[] args) {
//創建Map集合對象
Map<String, Integer> map = new HashMap<>();
map.put("趙麗穎", 168);
map.put("楊穎", 165);
map.put("林志玲", 178);
//1.使用Map集合中的方法keySet(),把Map集合所有的key取出來,存儲到一個Set集合中
Set<String> set = map.keySet();
//2.遍歷set集合,獲取Map集合中的每一個key
//使用迭代器遍歷Set集合
Iterator<String> it = set.iterator();
while (it.hasNext()) {
String key = it.next();
//3.通過Map集合中的方法get(key),通過key找到value
Integer value = map.get(key);
System.out.println(key + "=" + value);
}
System.out.println("-------------------");
//使用增強for遍歷Set集合
for (String key : set) {
//3.通過Map集合中的方法get(key),通過key找到value
Integer value = map.get(key);
System.out.println(key + "=" + value);
}
System.out.println("-------------------");
//使用增強for遍歷Set集合
for (String key : map.keySet()) {
//3.通過Map集合中的方法get(key),通過key找到value
Integer value = map.get(key);
System.out.println(key + "=" + value);
}
}
}
Entry鍵值對對象
- 我們已經知道, Map 中存放的是兩種對象,一種稱爲key(鍵),一種稱爲value(值),它們在在 Map 中是一一對應關係,這一對對象又稱做 Map 中的一個 Entry(項) 。 Entry 將鍵值對的對應關係封裝成了對象。即鍵值對對象,這樣我們在遍歷 Map 集合時,就可以從每一個鍵值對( Entry )對象中獲取對應的鍵與對應的值。既然Entry表示了一對鍵和值,那麼也同樣提供了獲取對應鍵和對應值得方法:
- public K getKey() :獲取Entry對象中的鍵。
- public V getValue() :獲取Entry對象中的值。
在Map集合中也提供了獲取所有Entry對象的方法:
- public Set<Map.Entry<K,V>> entrySet() : 獲取到Map集合中所有的鍵值對對象的集合(Set集合)。
鍵值對方式:即通過集合中每個鍵值對(Entry)對象,獲取鍵值對(Entry)對象中的鍵與值。
操作步驟:
- 獲取Map集合中,所有的鍵值對(Entry)對象,以Set集合形式返回。方法提示: entrySet() 。
- 遍歷包含鍵值對(Entry)對象的Set集合,得到每一個鍵值對(Entry)對象。
- 通過鍵值對(Entry)對象,獲取Entry對象中的鍵與值。 方法提示: getkey() getValue()
代碼舉例
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/*
Map集合遍歷的第二種方式:使用Entry對象遍歷
Map集合中的方法:
Set<Map.Entry<K,V>> entrySet() 返回此映射中包含的映射關係的 Set 視圖。
實現步驟:
1.使用Map集合中的方法entrySet(),把Map集合中多個Entry對象取出來,存儲到一個Set集合中
2.遍歷Set集合,獲取每一個Entry對象
3.使用Entry對象中的方法getKey()和getValue()獲取鍵與值
*/
public class Demo03EntrySet {
public static void main(String[] args) {
//創建Map集合對象
Map<String,Integer> map = new HashMap<>();
map.put("趙麗穎",168);
map.put("楊穎",165);
map.put("林志玲",178);
//1.使用Map集合中的方法entrySet(),把Map集合中多個Entry對象取出來,存儲到一個Set集合中
Set<Map.Entry<String, Integer>> set = map.entrySet();
//2.遍歷Set集合,獲取每一個Entry對象
//使用迭代器遍歷Set集合
Iterator<Map.Entry<String, Integer>> it = set.iterator();
while(it.hasNext()){
Map.Entry<String, Integer> entry = it.next();
//3.使用Entry對象中的方法getKey()和getValue()獲取鍵與值
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key+"="+value);
}
System.out.println("-----------------------");
for(Map.Entry<String,Integer> entry:set){
//3.使用Entry對象中的方法getKey()和getValue()獲取鍵與值
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key+"="+value);
}
}
}
Collections工具類
- Collections 是一個操作 Set、List 和 Map 等集合的工具類 。Collections 中提供了一系列靜態的方法對集合元素進行排序、查詢和修改等操作, 還提供了對集合對象設置不可變、對集合對象實現同步控制等方法。
排序操作:(均爲static方法)
- reverse(List):反轉 List 中元素的順序
- shuffle(List):對 List 集合元素進行隨機排序
- sort(List):根據元素的自然順序對指定 List 集合元素按升序排序
- sort(List,Comparator):根據指定的 Comparator 產生的順序對 List 集合元素進行排序
- swap(List,int, int):將指定 list 集合中的 i 處元素和 j 處元素進行交換
查找、替換
- Object max(Collection):根據元素的自然順序,返回給定集合中的最大元素
- Object max(Collection,Comparator):根據 Comparator 指定的順序,返回 給定集合中的最大元素
- Object min(Collection)
- Object min(Collection,Comparator)
- int frequency(Collection,Object):返回指定集合中指定元素的出現次數
- void copy(List dest,List src):將src中的內容複製到dest中
- boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替換 List 對象的所有舊值
Collections 類中提供了多個 synchronizedXxx() 方法,該方法可使將指定集 合包裝成線程同步的集合,從而可以解決多線程併發訪問集合時的線程安全 問題
package com.atguigu.java;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Collections:操作Collection、Map的工具類
*
*/
public class CollectionsTest {
/*
reverse(List):反轉 List 中元素的順序
shuffle(List):對 List 集合元素進行隨機排序
sort(List):根據元素的自然順序對指定 List 集合元素按升序排序
sort(List,Comparator):根據指定的 Comparator 產生的順序對 List 集合元素進行排序
swap(List,int, int):將指定 list 集合中的 i 處元素和 j 處元素進行交換
Object max(Collection):根據元素的自然順序,返回給定集合中的最大元素
Object max(Collection,Comparator):根據 Comparator 指定的順序,返回給定集合中的最大元素
Object min(Collection)
Object min(Collection,Comparator)
int frequency(Collection,Object):返回指定集合中指定元素的出現次數
void copy(List dest,List src):將src中的內容複製到dest中
boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替換 List 對象的所有舊值
*/
@Test
public void test2(){
List list = new ArrayList();
list.add(123);
list.add(43);
list.add(765);
list.add(-97);
list.add(0);
//報異常:IndexOutOfBoundsException("Source does not fit in dest")
// List dest = new ArrayList();
// Collections.copy(dest,list);
//正確的:
List dest = Arrays.asList(new Object[list.size()]);
System.out.println(dest.size());//list.size();
Collections.copy(dest,list);
System.out.println(dest);
/*
Collections 類中提供了多個 synchronizedXxx() 方法,
該方法可使將指定集合包裝成線程同步的集合,從而可以解決
多線程併發訪問集合時的線程安全問題
*/
//返回的list1即爲線程安全的List
List list1 = Collections.synchronizedList(list);
}
@Test
public void test1(){
List list = new ArrayList();
list.add(123);
list.add(43);
list.add(765);
list.add(765);
list.add(765);
list.add(-97);
list.add(0);
System.out.println(list);
// Collections.reverse(list);
// Collections.shuffle(list);
// Collections.sort(list);
// Collections.swap(list,1,2);
int frequency = Collections.frequency(list, 123);
System.out.println(list);
System.out.println(frequency);
}
}
計算一個字符串中每個字符出現次數
import java.util.HashMap;
import java.util.Scanner;
/*
分析:
1.使用Scanner獲取用戶輸入的字符串
2.創建Map集合,key是字符串中的字符,value是字符的個數
3.遍歷字符串,獲取每一個字符
4.使用獲取到的字符,去Map集合判斷key是否存在
key存在:
通過字符(key),獲取value(字符個數)
value++
put(key,value)把新的value存儲到Map集合中
key不存在:
put(key,1)
5.遍歷Map集合,輸出結果
*/
public class Demo03MapTest {
public static void main(String[] args) {
//1.使用Scanner獲取用戶輸入的字符串
Scanner sc = new Scanner(System.in);
System.out.println("請輸入一個字符串:");
String str = sc.next();
//2.創建Map集合,key是字符串中的字符,value是字符的個數
HashMap<Character, Integer> map = new HashMap<>();
//3.遍歷字符串,獲取每一個字符
for (char c : str.toCharArray()) {
//4.使用獲取到的字符,去Map集合判斷key是否存在
if (map.containsKey(c)) {
//key存在
Integer value = map.get(c);
value++;
map.put(c, value);
} else {
//key不存在
map.put(c, 1);
}
}
//5.遍歷Map集合,輸出結果
for (Character key : map.keySet()) {
Integer value = map.get(key);
System.out.println(key + "=" + value);
}
}
}