1. 程式人生 > >集合(Map、可變參數、Collections)

集合(Map、可變參數、Collections)

參數 es2017 抽象類 ati 子類 存取 stat 需求 規則

集合

第1章 Map接口

1.1 Map接口概述

我們通過查看Map接口描述,發現Map接口下的集合與Collection接口下的集合,它們存儲數據的形式不同,如下圖。

l Collection中的集合,元素是孤立存在的(理解為單身),向集合中存儲元素采用一個個元素的方式存儲。

l Map中的集合,元素是成對存在的(理解為夫妻)。每個元素由鍵與值兩部分組成,通過鍵可以找對所對應的值。

l Collection中的集合稱為單列集合,Map中的集合稱為雙列集合。

l 需要註意的是,Map中的集合不能包含重復的鍵,值可以重復;每個鍵只能對應一個值。

l Map中常用的集合為HashMap集合、LinkedHashMap集合。

技術分享

1.2 Map接口中常用集合概述

通過查看Map接口描述,看到Map有多個子類,這裏我們主要講解常用的HashMap集合、LinkedHashMap集合。

l HashMap<K,V>:存儲數據采用的哈希表結構,元素的存取順序不能保證一致。由於要保證鍵的唯一、不重復,需要重寫鍵的hashCode()方法、equals()方法。

l LinkedHashMap<K,V>HashMap下有個子類LinkedHashMap,存儲數據采用的哈希表結構+鏈表結構。通過鏈表結構可以保證元素的存取順序一致;通過哈希表結構可以保證的鍵的唯一、不重復,需要重寫鍵的hashCode()方法、equals()方法。

l 註意Map接口中的集合都有兩個泛型變量<K,V>,在使用時,要為兩個泛型變量賦予數據類型。兩個泛型變量<K,V>的數據類型可以相同,也可以不同。

1.3 Map接口中的常用方法

技術分享

l put方法:將指定的鍵與值對應起來,並添加到集合中

l 方法返回值為鍵所對應的值

使用put方法時,若指定的鍵(key)在集合中沒有,則沒有這個鍵對應的值,返回null,並把指定的鍵值添加到集合中;

使用put方法時,若指定的鍵(key)在集合中存在,則返回值為集合中鍵對應的值(該值為替換前的值),並把指定鍵所對應的值,替換成指定的新值。

l get方法:獲取指定鍵(key)所對應的值(value)

l remove方法:根據指定的鍵(key)刪除元素,返回被刪除元素的值(value)。

Map接口的方法演示

public class MapDemo {

public static void main(String[] args) {

//創建Map對象

Map<String, String> map = new HashMap<String,String>();

//map中添加元素

map.put("星期一", "Monday");

map.put("星期日", "Sunday");

System.out.println(map); // {星期日=Sunday, 星期一=Monday}

//當給Map中添加元素,會返回key對應的原來的value值,若key沒有對應的值,返回null

System.out.println(map.put("星期一", "Mon")); // Monday

System.out.println(map); // {星期日=Sunday, 星期一=Mon}

//根據指定的key獲取對應的value

String en = map.get("星期日");

System.out.println(en); // Sunday

//根據key刪除元素,會返回key對應的value

String value = map.remove("星期日");

System.out.println(value); // Sunday

System.out.println(map); // {星期一=Mon}

}

}

1.4 Map集合遍歷鍵找值方式

鍵找值方式:即通過元素中的鍵,獲取鍵所對應的值

操作步驟與圖解:

1.獲取Map集合中所有的鍵,由於鍵是唯一的,所以返回一個Set集合存儲所有的鍵

技術分享

2.遍歷鍵的Set集合,得到每一個鍵

3.根據鍵,獲取鍵所對應的值

技術分享

代碼演示:

public class MapDemo {

public static void main(String[] args) {

//創建Map對象

Map<String, String> map = new HashMap<String,String>();

//map中添加元素

map.put("鄧超", "孫儷");

map.put("李晨", "範冰冰");

map.put("劉德華", "柳巖");

//獲取Map中的所有key

Set<String> keySet = map.keySet();

//遍歷存放所有keySet集合

Iterator<String> it =keySet.iterator();

while(it.hasNext()){

//得到每一個key

String key = it.next();

//通過key獲取對應的value

String value = map.get(key);

System.out.println(key+"="+value);

}

}

}

1.5 Entry鍵值對對象

Map類設計時,提供了一個嵌套接口:EntryEntry將鍵值對的對應關系封裝成了對象。即鍵值對對象,這樣我們在遍歷Map集合時,就可以從每一個鍵值對(Entry)對象中獲取對應的鍵與對應的值。

技術分享

l Entry是Map接口中提供的一個靜態內部嵌套接口。

技術分享

l getKey()方法:獲取Entry對象中的鍵

l getValue()方法:獲取Entry對象中的值

技術分享

l entrySet()方法:用於返回Map集合中所有的鍵值對(Entry)對象,以Set集合形式返回。

1.6 Map集合遍歷鍵值對方式

鍵值對方式:即通過集合中每個鍵值對(Entry)對象,獲取鍵值對(Entry)對象中的鍵與值。

操作步驟與圖解:

1.獲取Map集合中,所有的鍵值對(Entry)對象,以Set集合形式返回。

技術分享

2.遍歷包含鍵值對(Entry)對象的Set集合,得到每一個鍵值對(Entry)對象

3.通過鍵值對(Entry)對象,獲取Entry對象中的鍵與值。

技術分享

技術分享

public class MapDemo {

public static void main(String[] args) {

//創建Map對象

Map<String, String> map = new HashMap<String,String>();

//map中添加元素

map.put("鄧超", "孫儷");

map.put("李晨", "範冰冰");

map.put("劉德華", "柳巖");

//獲取Map中的所有keyvalue的對應關系

Set<Map.Entry<String,String>> entrySet = map.entrySet();

//遍歷Set集合

Iterator<Map.Entry<String,String>> it =entrySet.iterator();

while(it.hasNext()){

//得到每一對對應關系

Map.Entry<String,String> entry = it.next();

//通過每一對對應關系獲取對應的key

String key = entry.getKey();

//通過每一對對應關系獲取對應的value

String value = entry.getValue();

System.out.println(key+"="+value);

}

}

}

註意:Map集合不能直接使用叠代器或者foreach進行遍歷。但是轉成Set之後就可以使用了。

1.7 HashMap存儲自定義類型鍵值

練習:每位學生(姓名,年齡)都有自己的家庭住址。那麽,既然有對應關系,則將學生對象和家庭住址存儲到map集合中。學生作為鍵, 家庭住址作為值。

註意,學生姓名相同並且年齡相同視為同一名學生。

l 學生類

public class Student {

private String name;

private int age;

//編寫構造方法,文檔中已省略

//編寫get,set方法,文檔中已省略

//編寫toString方法,文檔中已省略

}

l 測試類

public class HashMapTest {

public static void main(String[] args) {

//1,創建hashmap集合對象。

Map<Student,String> map = new HashMap<Student,String>();

//2,添加元素。

map.put(new Student("lisi",28), "上海");

map.put(new Student("wangwu",22), "北京");

map.put(new Student("zhaoliu",24), "成都");

map.put(new Student("zhouqi",25), "廣州");

map.put(new Student("wangwu",22), "南京");

//3,取出元素。鍵找值方式

Set<Student> keySet = map.keySet();

for(Student key : keySet){

String value = map.get(key);

System.out.println(key.toString()+"....."+value);

}

//取出元素。鍵值對方式

Set<Map.Entry<Student, String>> entrySet = map.entrySet();

for (Map.Entry<Student, String> entry : entrySet) {

Student key = entry.getKey();

String value = entry.getValue();

System.out.println(key.toString()+"....."+value);

}

}

}

l 當給HashMap中存放自定義對象時,如果自定義對象作為key存在,這時要保證對象唯一,必須復寫對象的hashCode和equals方法(如果忘記,請回顧HashSet存放自定義對象)。

l 如果要保證map中存放的key和取出的順序一致,可以使用LinkedHashMap集合來存放。

1.8 靜態導入

在導包的過程中我們可以直接導入靜態部分,這樣某個類的靜態成員就可以直接使用了。在源碼中經常會出現靜態導入。

靜態導入格式:

import static XXX.YYY; 導入後YYY可直接使用。

例如:Map.Entry的訪問,簡化後為Entry

import static java.util.Map.Entry;

public class HashMapTest {

public static void main(String[] args) {

//1,創建hashmap集合對象。

Map<Student,String> map = new HashMap<Student,String>();

//取出元素。鍵值對方式

//Set<Map.Entry<Student, String>> entrySet = map.entrySet();

Set<Entry<Student, String>> entrySet = map.entrySet();

//for (Map.Entry<Student, String> entry : entrySet) {

for (Entry<Student, String> entry : entrySet) {

Student key = entry.getKey();

String value = entry.getValue();

System.out.println(key.toString()+"....."+value);

}

}

}

1.9 可變參數

JDK1.5之後,如果我們定義一個方法需要接受多個參數,並且多個參數類型一致,我們可以對其簡化成如下格式:

修飾符 返回值類型 方法名(參數類型... 形參名){ }

其實這個書寫完全等價與

修飾符 返回值類型 方法名(參數類型[] 形參名){ }

只是後面這種定義,在調用時必須傳遞數組,而前者可以直接傳遞數據即可。

jdk1.5以後。出現了簡化操作。... 用在參數上,稱之為可變參數。

同樣是代表數組,但是在調用這個帶有可變參數的方法時,不用創建數組(這就是簡單之處),直接將數組中的元素作為實際參數進行傳遞,其實編譯成的class文件,將這些元素先封裝到一個數組中,在進行傳遞。這些動作都在編譯.class文件時,自動完成了。

代碼演示:

public class ParamDemo {

public static void main(String[] args) {

int[] arr = {21,89,32};

int sum = add(arr);

System.out.println(sum);

sum = add(21,89,32);//可變參數調用形式

System.out.println(sum);

}

//JDK1.5之後寫法

public static int add(int...arr){

int sum = 0;

for (int i = 0; i < arr.length; i++) {

sum += arr[i];

}

return sum;

}

//原始寫法

/*

public static int add(int[] arr) {

int sum = 0;

for (int i = 0; i < arr.length; i++) {

sum += arr[i];

}

return sum;

}

*/

}

l 上述add方法在同一個類中,只能存在一個。因為會發生調用的不確定性

註意:如果在方法書寫時,這個方法擁有多參數,參數中包含可變參數,可變參數一定要寫在參數列表的末尾位置。

1.10 Collections集合工具類

Collections是集合工具類,用來對集合進行操作。部分方法如下:

技術分享

l public static <T> void sort(List<T> list) // 集合元素排序

//排序前元素list集合元素 [33,11,77,55]

Collections.sort( list );

//排序後元素list集合元素 [11,33,55,77]

l public static void shuffle(List<?> list) // 集合元素存儲位置打亂

//list集合元素 [11,33,55,77]

Collections.shuffle( list );

//使用shuffle方法後,集合中的元素為[77,33,11,55],每次執行該方法,集合中存儲的元素位置都會隨機打亂

1.11 集合嵌套

集合嵌套並不是一個新的知識點,僅僅是集合內容又是集合,如Collection集合嵌套、Collection集合與Map集合相互嵌套、Map集合嵌套。

l ArrayList嵌套 ArrayList

ArrayList< ArrayList<String> >

Collection< ArrayList<Integer> >

l Map嵌套 ArrayList

HashMap<String, ArrayList<Person>>

ArrayList< HashMap<String, String>>

l Map集合嵌套

HashMap<String, HashMap<String,String>>

HashMap<String, HashMap<Person,String>>

1.12 集合繼承體系的面向對象思想

技術分享

l 接口:用來明確所有集合中該具有的功能,相當於在定義集合功能標準;

l 抽象類:把多個集合中功能實現方式相同的方法,抽取到抽象類實現,具體集合不再遍寫,繼承使用即可;

l 具體類:繼承抽象類,實現接口,重寫所有抽象方法,達到具備指定功能的集合。每個具體集合類,根據自身的數據存儲結構方式,對接口中的功能方法,進行不同方式的實現。

第2章 模擬鬥地主洗牌發牌

2.1 案例介紹

按照鬥地主的規則,完成洗牌發牌的動作。

技術分享

具體規則:

1. 組裝54張撲克牌

2. 54張牌順序打亂

3. 三個玩家參與遊戲,三人交替摸牌,每人17張牌,最後三張留作底牌。

4. 查看三人各自手中的牌(按照牌的大小排序)、底牌

l 手中撲克牌從大到小的擺放順序:大王,小王,2,A,K,Q,J,10,9,8,7,6,5,4,3

2.2 案例需求分析

l 準備牌:

完成數字與紙牌的映射關系:

使用雙列Map(HashMap)集合,完成一個數字與字符串紙牌的對應關系(相當於一個字典)

l 洗牌:

通過數字完成洗牌發牌

l 發牌:

將每個人以及底牌設計為ArrayList<String>,將最後3張牌直接存放於底牌,剩余牌通過對3取模依次發牌。

存放的過程中要求數字大小與鬥地主規則的大小對應。

將代表不同紙牌的數字分配給不同的玩家與底牌。

l 看牌:

通過Map集合找到對應字符展示。

通過查詢紙牌與數字的對應關系,由數字轉成紙牌字符串再進行展示。

技術分享

2.3 實現代碼步驟

技術分享

首先,要修改java文件編碼,由GBK修改為UTF-8,因為默認的字符編碼GBK沒有我們要的梅花、方片、黑桃、紅桃(????)等特殊字符。

import java.util.ArrayList;

import java.util.Collections;

import java.util.HashMap;

/*

* 鬥地主洗牌發牌排序

*/

public class Poker {

public static void main(String[] args) {

//準備花色

ArrayList<String> color = new ArrayList<String>();

color.add("?");

color.add("?");

color.add("?");

color.add("?");

//準備數字

ArrayList<String> number = new ArrayList<String>();

Collections.addAll(number,"3","4","5","6","7","8","9","10","J","Q","K","A","2");

//定義一個map集合:用來將數字與每一張牌進行對應

HashMap<Integer, String> map = new HashMap<Integer, String>();

int index = 0;

for (String thisNumber : number) {

for (String thisColor : color) {

map.put(index++, thisColor+thisNumber);

}

}

//加入大小王

map.put(index++, "?");

map.put(index++, "?");

//一副54張的牌 ArrayList裏邊為0-53的數的新牌

ArrayList<Integer> cards = new ArrayList<Integer>();

for (int i = 0; i <= 53; i++) {

cards.add(i);

}

//洗牌

Collections.shuffle(cards);

//創建三個玩家和底牌

ArrayList<Integer> iPlayer = new ArrayList<Integer>();

ArrayList<Integer> iPlayer2 = new ArrayList<Integer>();

ArrayList<Integer> iPlayer3 = new ArrayList<Integer>();

ArrayList<Integer> itCards = new ArrayList<Integer>();

//遍歷這副洗好的牌,遍歷過程中,將牌發到三個玩家和底牌中

for (int i = 0; i < cards.size(); i++) {

if(i>=51) {

iCards.add(cards.get(i));

} else {

if(i%3==0) {

iPlayer.add(cards.get(i));

}else if(i%3==1) {

iPlayer2.add(cards.get(i));

}else {

iPlayer3.add(cards.get(i));

}

}

}

//對每個人手中的牌排序

Collections.sort(iPlayer);

Collections.sort(iPlayer2);

Collections.sort(iPlayer3);

//對應數字形式的每個人手中的牌,定義字符串形式的牌

ArrayList<String> sPlayer = new ArrayList<String>();

ArrayList<String> sPlayer2 = new ArrayList<String>();

ArrayList<String> sPlayer3 = new ArrayList<String>();

ArrayList<String> sCards = new ArrayList<String>();

for (Integer key : iPlayer) {

sPlayer.add(map.get(key));

}

for (Integer key : iPlayer2) {

sPlayer2.add(map.get(key));

}

for (Integer key : iPlayer3) {

sPlayer3.add(map.get(key));

}

for (Integer key : iCards) {

sCards.add(map.get(key));

}

//看牌

System.out.println(sPlayer);

System.out.println(sPlayer2);

System.out.println(sPlayer3);

System.out.println(sCards);

}

}

第3章 總結

3.1 知識點總結

l Map集合:

map集合中的元素都是成對出現,成對存儲的

map集合中的元素都是以一對鍵和值的形式組成存在的,稱為鍵值對,理解為夫妻對

map集合中的鍵不能重復存儲,值可以重復

map集合中的每一個鍵 對應著一個值

l 方法:

V put(K key, V value) 把指定的鍵與指定的值添加到Map集合中

V remove(Object key) 把指定的鍵 所對應的鍵值對元素 在Map集合中刪除,返回被刪除元素的值

Set<Map.Entry<K,V>> entrySet() 獲取到Map集合中所有的鍵值對對象的集合(Set集合)

V get(Object key) 根據指定的鍵,在Map集合中獲取對應的值

Set<K> keySet() 獲取Map集合中所有的鍵,存儲到Set集合中

l Map集合遍歷的兩種方式

l 方式1:根據鍵找值的方式

//a, 獲取到Map集合中所有的鍵,返回對應的Set集合

//b, 遍歷鍵的集合,獲取到每一個鍵

//c, 通過鍵,找到對應的值

//獲取到Map集合中所有的鍵,返回對應的Set集合

Set<String> keys = map.keySet();

//遍歷鍵的集合,獲取到每一個鍵

for (String key : keys) {

//通過鍵,找到對應的值

Student s = map.get(key);

System.out.println( key + "..." + s.getName() + "..." + s.getAge() );

}

l 方式2:根據鍵值對對象找鍵和值的方式

//a, 獲取Map集合中所有的鍵值對元素,返回對應的Set集合

//b, 遍歷鍵值對元素集合,獲取到每一個鍵值對元素對象

//c, 通過鍵值對元素對象,獲取對應的鍵,和對應的值

//獲取Map集合中所有的鍵值對元素,返回對應的Set集合

Set< Map.Entry<String, Student>> entrySet = map.entrySet();

//遍歷鍵值對元素集合,獲取到每一個鍵值對元素對象

for (Map.Entry<String, Student> entry : entrySet) {

//通過鍵值對元素對象,獲取對應的鍵,和對應的值

//找鍵

String key = entry.getKey();

//找值

Student s = entry.getValue();

//打印

System.out.println( key+"..."+s.getName()+"..."+s.getAge() );

}

l HashMap:

l 特點:

Map集合的子集合

底層采用哈希表結構

HashMap集合中的key不能重復,通過重寫hashCode() equals()方法來保證鍵的唯一。

不能保證元素存與取的順序完全一致

l LinkedHashMap:

l 特點:

HashMap集合的子集合

底層采用哈希表+鏈表結構

LinkedHashMap集合中的key不能重復,通過重寫hashCode() equals()方法來保證鍵的唯一。

l Collections中的方法:

public static <T> void sort(List<T> list) 排序

public static void shuffle(List<?> list) 集合中的元素存儲位置隨機打亂

集合(Map、可變參數、Collections)