Map
将鍵映射到值的對象,一個映射不能包含重複的鍵,每個鍵最多隻能映射到一個值。除此之外你得明确的是Map是一個接口你得使用實作Map的類來執行個體化。其次是Map中資料存儲格式是K-V鍵值對方法存儲。
Map接口和Collection接口的不同
- Map是雙列的,Collection是單列的
- Map的鍵唯一,Collection的子體系Set是唯一的
- Map集合的資料結構值針對鍵有效,跟值無關
- Collection集合的資料結構是針對元素有效
Map集合常用功能
- 添加功能
- V put(K key,V value):添加元素。
- 如果鍵是第一次存儲,就直接存儲鍵值對元素,傳回null
- 如果鍵不是第一次存在,就用值把以前的值替換掉,傳回以前的值
- V put(K key,V value):添加元素。
- 删除功能
- V remove(Object key):根據鍵删除鍵值對元素,并把值傳回
- 判斷功能
- boolean containsKey(Object key):判斷集合是否包含指定的鍵
- boolean containsValue(Object value):判斷集合是否包含指定的值
- boolean isEmpty():判斷集合是否為空
- 擷取功能
- Set<Map.Entry<K,V>> entrySet():傳回此映射中包含的映射關系的 Set 視圖,也就是傳回一個鍵值對整體。
- V get(Object key):根據鍵擷取值
- Set keySet():擷取集合中所有鍵的集合
- Collection values():擷取集合中所有值的集合
- 長度功能
- int size():傳回集合中的鍵值對的對數
代碼執行個體
public class MapDemo {
public static void main(String[] args) {
// 建立集合對象
Map<String, String> map = new HashMap<String, String>();
// 添加元素
// System.out.println("put:" + map.put("文章", "馬伊俐"));
// System.out.println("put:" + map.put("文章", "姚笛"));
map.put("鄧超", "孫俪");
map.put("黃曉明", "楊穎");
map.put("周傑倫", "蔡依林");
map.put("劉恺威", "楊幂");
// void clear():移除所有的鍵值對元素
// map.clear();
// V remove(Object key):根據鍵删除鍵值對元素,并把值傳回
// System.out.println("remove:" + map.remove("黃曉明"));
// System.out.println("remove:" + map.remove("黃曉波"));
// boolean containsKey(Object key):判斷集合是否包含指定的鍵
// System.out.println("containsKey:" + map.containsKey("黃曉明"));
// System.out.println("containsKey:" + map.containsKey("黃曉波"));
// boolean isEmpty():判斷集合是否為空
// System.out.println("isEmpty:"+map.isEmpty());
//int size():傳回集合中的鍵值對的對數
System.out.println("size:"+map.size());
// 輸出集合名稱
System.out.println("map:" + map);
}
}
擷取功能:
public class MapDemo2 {
public static void main(String[] args) {
// 建立集合對象
Map<String, String> map = new HashMap<String, String>();
// 建立元素并添加元素
map.put("鄧超", "孫俪");
map.put("黃曉明", "楊穎");
map.put("周傑倫", "蔡依林");
map.put("劉恺威", "楊幂");
// V get(Object key):根據鍵擷取值
System.out.println("get:" + map.get("周傑倫"));
System.out.println("get:" + map.get("周傑")); // 傳回null
System.out.println("----------------------");
// Set<K> keySet():擷取集合中所有鍵的集合
Set<String> set = map.keySet();
// 周遊Set 增強for 或者疊代器 反正就是Collection的周遊方式
for (String key : set) {
System.out.println(key);
}
System.out.println("----------------------");
// Collection<V> values():擷取集合中所有值的集合
Collection<String> con = map.values();
for (String value : con) {
System.out.println(value);
}
}
}
Map集合的周遊:
周遊思路一: A:擷取所有的鍵–> B:周遊鍵的集合,擷取得到每一個鍵 -->C:根據鍵去找值。
示例:
// 建立集合對象
Map<String, String> map = new HashMap<String, String>();
// 建立元素并添加到集合
map.put("楊過", "小龍女");
map.put("郭靖", "黃蓉");
map.put("楊康", "穆念慈");
map.put("陳玄風", "梅超風");
// 周遊
// 擷取所有的鍵
Set<String> set = map.keySet();
// 周遊鍵的集合,擷取得到每一個鍵
for (String key : set) {
// 根據鍵去找值
String value = map.get(key);
System.out.println(key + "---" + value);
}
周遊思路二: A:擷取所有鍵值對對象的集合–>B:周遊鍵值對對象的集合,得到每一個鍵值對對象–>C:根據鍵值對對象擷取鍵和值。
示例:
// 建立集合對象
Map<String, String> map = new HashMap<String, String>();
// 建立元素并添加到集合
map.put("楊過", "小龍女");
map.put("郭靖", "黃蓉");
map.put("楊康", "穆念慈");
map.put("陳玄風", "梅超風");
// 擷取所有鍵值對對象的集合
Set<Map.Entry<String, String>> set = map.entrySet();
// 周遊鍵值對對象的集合,得到每一個鍵值對對象
for (Map.Entry<String, String> me : set) {
// 根據鍵值對對象擷取鍵和值
String key = me.getKey();
String value = me.getValue();
System.out.println(key + "---" + value);
}
圖示對比:
HashMap
鍵是哈希表結構,可以保證鍵的唯一性.需要注意的是當鍵為類類型的時候,需要重寫類的equals和hashcode方法.
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
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 (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
LinkedHashMap
Map 接口的哈希表和連結清單實作,具有可預知的疊代順序。此實作與 HashMap 的不同之處在于,後者維護着一個運作于所有條目的雙重連結清單。此連結清單定義了疊代順序,該疊代順序通常就是将鍵插入到映射中的順序(插入順序)。
TreeMap
鍵是紅黑樹結構,可以保證鍵的排序和唯一性。無參構造則是自然排序,前面的文章說過了。
示例:
// 建立集合對象
TreeMap<Student, String> tm = new TreeMap<Student, String>(
new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
// 主要條件
int num = s1.getAge() - s2.getAge();
// 次要條件
int num2 = num == 0 ? s1.getName().compareTo(
s2.getName()) : num;
return num2;
}
});
// 建立學生對象
Student s1 = new Student("潘安", 30);
Student s2 = new Student("柳下惠", 35);
Student s3 = new Student("唐伯虎", 33);
Student s4 = new Student("燕青", 32);
Student s5 = new Student("唐伯虎", 33);
// 存儲元素
tm.put(s1, "宋朝");
tm.put(s2, "元朝");
tm.put(s3, "明朝");
tm.put(s4, "清朝");
tm.put(s5, "漢朝");
// 周遊
Set<Student> set = tm.keySet();
for (Student key : set) {
String value = tm.get(key);
System.out.println(key.getName() + "---" + key.getAge() + "---"
+ value);
}
統計字元串中每個字元出現次數:
圖解思路
示例代碼
/*
* 需求 :"aababcabcdabcde",擷取字元串中每一個字母出現的次數要求結果:a(5)b(4)c(3)d(2)e(1)
*
* 分析:
* A:定義一個字元串(可以改進為鍵盤錄入)
* B:定義一個TreeMap集合
* 鍵:Character
* 值:Integer
* C:把字元串轉換為字元數組
* D:周遊字元數組,得到每一個字元
* E:拿剛才得到的字元作為鍵到集合中去找值,看傳回值
* 是null:說明該鍵不存在,就把該字元作為鍵,1作為值存儲
* 不是null:說明該鍵存在,就把值加1,然後重寫存儲該鍵和值
* F:定義字元串緩沖區變量
* G:周遊集合,得到鍵和值,進行按照要求拼接
* H:把字元串緩沖區轉換為字元串輸出
*
* 錄入:linqingxia
* 結果:result:a(1)g(1)i(3)l(1)n(2)q(1)x(1)
*/
public class TreeMapDemo {
public static void main(String[] args) {
// 定義一個字元串(可以改進為鍵盤錄入)
Scanner sc = new Scanner(System.in);
System.out.println("請輸入一個字元串:");
String line = sc.nextLine();
// 定義一個TreeMap集合
TreeMap<Character, Integer> tm = new TreeMap<Character, Integer>();
//把字元串轉換為字元數組
char[] chs = line.toCharArray();
//周遊字元數組,得到每一個字元
for(char ch : chs){
//拿剛才得到的字元作為鍵到集合中去找值,看傳回值
Integer i = tm.get(ch);
//是null:說明該鍵不存在,就把該字元作為鍵,1作為值存儲
if(i == null){
tm.put(ch, 1);
}else {
//不是null:說明該鍵存在,就把值加1,然後重寫存儲該鍵和值
i++;
tm.put(ch,i);
}
}
//定義字元串緩沖區變量
StringBuilder sb= new StringBuilder();
//周遊集合,得到鍵和值,進行按照要求拼接
Set<Character> set = tm.keySet();
for(Character key : set){
Integer value = tm.get(key);
sb.append(key).append("(").append(value).append(")");
}
//把字元串緩沖區轉換為字元串輸出
String result = sb.toString();
System.out.println("result:"+result);
}
}
Collections 類
public class Collectionsextends Object 是一個針對集合操作的工具類,都是靜态方法。
常見的幾個小方法:
A:public static <T> void sort(List<T> list) 預設情況自然排序
B:public static <T> int binarySearch(List<?> list,T key) 二分查找
C:public static <T> T max(Collection<?> coll) 最大值
D:public static void reverse(List<?> list)翻轉
E:public static void shuffle(List<?> list)随機置換
案例
- 基礎方法使用
public static void main(String[] args) {
// 建立集合對象
List<Integer> list = new ArrayList<Integer>();
// 添加元素
list.add(30);
list.add(20);
list.add(50);
list.add(10);
list.add(40);
System.out.println("list:" + list);
// public static <T> void sort(List<T> list):排序 預設情況下是自然順序。
// Collections.sort(list);
// System.out.println("list:" + list);
// [10, 20, 30, 40, 50]
// public static <T> int binarySearch(List<?> list,T key):二分查找
// System.out
// .println("binarySearch:" + Collections.binarySearch(list, 30));
// System.out.println("binarySearch:"
// + Collections.binarySearch(list, 300));
// public static <T> T max(Collection<?> coll):最大值
// System.out.println("max:"+Collections.max(list));
// public static void reverse(List<?> list):反轉
// Collections.reverse(list);
// System.out.println("list:" + list);
//public static void shuffle(List<?> list):随機置換
Collections.shuffle(list);
System.out.println("list:" + list);
}
- 自定義對象排序
// 建立集合對象
List<Student> list = new ArrayList<Student>();
// 建立學生對象
Student s1 = new Student("林青霞", 27);
Student s2 = new Student("風清揚", 30);
Student s3 = new Student("劉曉曲", 28);
Student s4 = new Student("武鑫", 29);
Student s5 = new Student("林青霞", 27);
// 添加元素對象
list.add(s1);
list.add(s2);
list.add(s3);
list.add(s4);
list.add(s5);
// 排序
// 自然排序
// Collections.sort(list);
// 比較器排序
// 如果同時有自然排序和比較器排序,以比較器排序為主
Collections.sort(list, new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
int num = s2.getAge() - s1.getAge();
int num2 = num == 0 ? s1.getName().compareTo(s2.getName())
: num;
return num2;
}
});
// 周遊集合
for (Student s : list) {
System.out.println(s.getName() + "---" + s.getAge());
}
- 模拟鬥地主洗牌發牌
import java.util.ArrayList;
import java.util.Collections;
/*
* 模拟鬥地主洗牌和發牌
*
* 分析:
* A:建立一個牌盒
* B:裝牌
* C:洗牌
* D:發牌
* E:看牌
*/
public class PokerDemo {
public static void main(String[] args) {
// 建立一個牌盒
ArrayList<String> array = new ArrayList<String>();
// 裝牌
// 黑桃A,黑桃2,黑桃3,...黑桃K
// 紅桃A,...
// 梅花A,...
// 方塊A,...
// 定義一個花色數組
String[] colors = { "♠", "♥", "♣", "♦" };
// 定義一個點數數組
String[] numbers = { "A", "2", "3", "4", "5", "6", "7", "8", "9", "10",
"J", "Q", "K" };
// 裝牌
for (String color : colors) {
for (String number : numbers) {
array.add(color.concat(number));
}
}
array.add("小王");
array.add("大王");
// 洗牌
Collections.shuffle(array);
// System.out.println("array:" + array);
// 發牌
ArrayList<String> xianglei = new ArrayList<String>();
ArrayList<String> linQingXia = new ArrayList<String>();
ArrayList<String> liuYi = new ArrayList<String>();
ArrayList<String> diPai = new ArrayList<String>();
for (int x = 0; x < array.size(); x++) {
if (x >= array.size() - 3) {
diPai.add(array.get(x));
} else if (x % 3 == 0) {
fengQingYang.add(array.get(x));
} else if (x % 3 == 1) {
linQingXia.add(array.get(x));
} else if (x % 3 == 2) {
liuYi.add(array.get(x));
}
}
// 看牌
lookPoker("向磊", fengQingYang);
lookPoker("林青霞", linQingXia);
lookPoker("劉意", liuYi);
lookPoker("底牌", diPai);
}
public static void lookPoker(String name, ArrayList<String> array) {
System.out.print(name + "的牌是:");
for (String s : array) {
System.out.print(s + " ");
}
System.out.println();
}
}
如何對發出來的牌進行排序?
圖解:
代碼
/*
* 思路:
* A:建立一個HashMap集合
* B:建立一個ArrayList集合
* C:建立花色數組和點數數組
* D:從0開始往HashMap裡面存儲編号,并存儲對應的牌
* 同時往ArrayList裡面存儲編号即可。
* E:洗牌(洗的是編号)
* F:發牌(發的也是編号,為了保證編号是排序的,就建立TreeSet集合接收)
* G:看牌(周遊TreeSet集合,擷取編号,到HashMap集合找對應的牌)
*/
public class PokerDemo {
public static void main(String[] args) {
// 建立一個HashMap集合
HashMap<Integer, String> hm = new HashMap<Integer, String>();
// 建立一個ArrayList集合
ArrayList<Integer> array = new ArrayList<Integer>();
// 建立花色數組和點數數組
// 定義一個花色數組
String[] colors = { "♠", "♥", "♣", "♦" };
// 定義一個點數數組
String[] numbers = { "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q",
"K", "A", "2", };
// 從0開始往HashMap裡面存儲編号,并存儲對應的牌,同時往ArrayList裡面存儲編号即可。
int index = 0;
for (String number : numbers) {
for (String color : colors) {
String poker = color.concat(number);
hm.put(index, poker);
array.add(index);
index++;
}
}
hm.put(index, "小王");
array.add(index);
index++;
hm.put(index, "大王");
array.add(index);
// 洗牌(洗的是編号)
Collections.shuffle(array);
// 發牌(發的也是編号,為了保證編号是排序的,就建立TreeSet集合接收)
TreeSet<Integer> fengQingYang = new TreeSet<Integer>();
TreeSet<Integer> linQingXia = new TreeSet<Integer>();
TreeSet<Integer> liuYi = new TreeSet<Integer>();
TreeSet<Integer> diPai = new TreeSet<Integer>();
for (int x = 0; x < array.size(); x++) {
if (x >= array.size() - 3) {
diPai.add(array.get(x));
} else if (x % 3 == 0) {
fengQingYang.add(array.get(x));
} else if (x % 3 == 1) {
linQingXia.add(array.get(x));
} else if (x % 3 == 2) {
liuYi.add(array.get(x));
}
}
// 看牌(周遊TreeSet集合,擷取編号,到HashMap集合找對應的牌)
lookPoker("風清揚", fengQingYang, hm);
lookPoker("林青霞", linQingXia, hm);
lookPoker("劉意", liuYi, hm);
lookPoker("底牌", diPai, hm);
}
// 寫看牌的功能
public static void lookPoker(String name, TreeSet<Integer> ts,
HashMap<Integer, String> hm) {
System.out.print(name + "的牌是:");
for (Integer key : ts) {
String value = hm.get(key);
System.out.print(value + " ");
}
System.out.println();
}
}
總結
HashMap和Hashtable的差別?
- Hashtable:線程安全,效率低。不允許null鍵和null值
- HashMap:線程不安全,效率高。允許null鍵和null值
List,Set,Map等接口是否都繼承自Map接口?
- List,Set不是繼承自Map接口,它們繼承自Collection接口
- Map接口本身就是一個頂層接口
Collection和Collections的差別
- Collection 是單列集合的頂層接口,有兩個子接口List和Set
- Collections 是針對集合進行操作的工具類,可以對集合進行排序和查找等