自定義泛型
1.1、泛型的定義介紹
在集合中,不管是接口還是類,它們在定義的時候類或接口名的後面都使用,當我們在使用的時候,可以指定其中的類型。如果當前的類或接口中並沒有,我們在使用的時候也不能去指定類型。
舉例:比如我們之前所學習的集合ArrayList類:
說明:在ArrayList類上有一個泛型的參數:E設計API的時候,設計者並不知道我們要用ArrayList存儲哪種數據類型,所以他定義了一個泛型。然後當我們使用ArrayList的時候,我們知道要存儲的類型,比如要存儲String類型:
當我們new對象的時候,就把泛型E替換成了String,於是JVM就知道我們要存儲的其實是String。
泛型:如果我們不確定數據的類型,可以用一個標識符來代替。
如果我們在使用的時候已經確定要使用的數據類型了,我們在創建對象的時候可以指定使用的數據類型。
泛型自定義格式:這裡的標識符可以是任意的字母、數字、下劃線和 $ 。但是這裡一般規範使用單個大寫字母。注意:自定義泛型也屬於標識符,滿足標識符的命名規則。1)數字不能開始;2)關鍵字不能作為標識符;
根據以上分析我們可以思考一個問題:既然我們學習過的集合類可以定義泛型,那麼我們自己在描述類或接口的時候,是否也可以在自己的類或接口上定義泛型,然後別人使用的時候也可以指定這個類型呢?答案當然是可以的。
1.2、自定義泛型類(掌握)
泛型類:在定義類的時候,在類名的後面書寫泛型。格式:
<code> class 類名 { }/<code>
泛型參數其實就是標識符。
分析和步驟:1)創建測試類GenericDemo1 ,在這個類中定義一個main函數;2)定義一個泛型類Demo
<code>package cn.xuexi.generic.demo1;/* * 自定義泛型類演示 * 在類上定義的泛型,當外界創建這個對象的時候,由創建者指定泛型的類型 * 在類上定義的泛型,類中的成員變量和函數都可以使用 */class Demo{ ABC name; public void show(ABC name) { this.name=name; }}public class GenericDemo1 { public static void main(String[] args) { //創建Demo類的對象 /* * 注意如果這裡創建Demo類的對象時沒有指定泛型類的類型時,這裡ABC默認是Object類型 * 如下代碼所示創建Demo類的對象的時候,指定的泛型類類型是String類型, * 那麼Demo類中的泛型類ABC就是String類 * 同理,如果指定的數據類型是Integer,那麼ABC就是Integer類 */ //Demo<string> d=new Demo<string>(); Demo<integer> d=new Demo<integer>(); //d.show("哈哈"); d.show(123); System.out.println(d.name); }}/<integer>/<integer>/<string>/<string> /<code>
說明:1)在類上定義的泛型,當外界在創建這個類的對象的時候,需要創建者自己來明確當前泛型的具體類型;2)在類上定義的泛型,在類中的方法上和成員變量是可以使用的;3)上述代碼中如果創建Demo類的對象時沒有指定泛型類的類型時,那麼ABC默認是Object類型;4)上述代碼中如果創建Demo類的對象時指定的泛型類類型是String類型,那麼ABC默認是String類型;
自定義泛型類的練習:需求:使用自定義泛型模擬隊列數據結構。
分析:由於隊列是集合中的一種,可以存儲任意類型的數據,而對於隊列類我們不確定具體存儲什麼數據類型,所以可以在隊列類QueueDemo中指定泛型,根據創建者來決定什麼數據類型。
步驟:1)自定義一個類QueueDemo
自定義的隊列類:
<code>package cn.xuexi.generic.demo1;import java.util.LinkedList;/* * 模擬隊列 * 由於隊列是集合中的一種,可以存儲任意類型的數據,而對於隊列類我們不確定具體存儲什麼 * 數據類型,所以可以在隊列類QueueDemo中指定泛型,根據創建者來決定什麼類型 */public class QueueDemo{ //創建LinkedList集合的對象 LinkedList /<code>list=new LinkedList (); //自定義函數向隊列中添加數據 public void addElement(E e) { list.addLast(e); } //自定義函數取出隊列中的數據 public E getElement() { return list.removeFirst(); } //自定義函數判斷隊列中是否還含有數據 public boolean isNull() { /* * list.isEmpty() 表示集合中沒有數據返回true 有數據返回false * 我們這裡這麼書寫:!list.isEmpty() 表示集合中有數據返回true 沒有數據返回false */ return !list.isEmpty(); }}
定義測試類:
<code>package cn.xuexi.generic.demo1;/* * 測試模擬隊列的類 */public class GenericDemo2 { public static void main(String[] args) { //創建隊列類的對象,並指定數據類型 QueueDemo<string> qd = new QueueDemo<string>(); //使用對象調用函數向隊列中添加數據 qd.addElement("abc"); qd.addElement("hello"); qd.addElement("java"); //取出數據 while(qd.isNull()) { //表示有數據 String s = qd.getElement(); System.out.println(s); } }}/<string>/<string>/<code>
注意:對於自定義泛型類只有在創建這個類的對象的時候才可以指定泛型的類型。
1.3、在函數上使用泛型(掌握)
我們不僅可以在自己定義的類或接口上使用泛型,還可以在自定義的函數上使用泛型。雖然可以在類上定義泛型,但是有時類中的方法需要接收的數據類型和類上外界指定的類型不一致。也就是說對於某個函數而言參數的數據類型和所屬類的泛型類型不一致了,這時我們可以在這個類中的這個方法上單獨給這個方法設定泛型。
在函數上使用泛型的格式:
<code> 函數修飾符 函數返回值類型 方法名( 泛型名 變量名 ) { 函數體; }/<code>
說明:函數返回值類型前面的相當於定義了方法參數列表中泛型的類型。
代碼演示如下圖所示:
說明:1)類上的泛型是在創建這個類的對象的時候明確具體是什麼類型;2)方法上的泛型是在真正調用這個方法時,傳遞的是什麼類型,泛型就會自動變成什麼類型;舉例:上述代碼中當調用者傳遞的是2,那麼這個Q就代表Integer類型。如果調用者傳遞的是new Student(“班長”,19),那麼這個Q類型就是Student類型。3)上述method函數中表示定義的泛型,而參數列表中的Q q是在使用泛型類型,而這裡的Q類型具體由調用者來指定;
自定義泛型的練習:需求:自定義泛型方法,定義一個方法,可以打印任意一個數組的內容。打印String數組打印Integer數組
分析和步驟:1)分別定義一個String類型和Integer類型的數組,並分別存入數據;2)定義兩個函數都是printArray,但是參數列表不同,一個接收String類型的數組,另一個接收是Integer類型的數組;3)分別遍歷兩個數組;4)雖然上述做法可以,但是隻要遍歷不同類型的數組就得定義一個重載的函數,麻煩,我們可以使用在函數上自定義泛型
<code>package cn.xuexi.generic.demo1;/* * 需求:自定義泛型方法,定義一個方法,可以打印任意一個數組的內容。 打印String數組 打印Integer數組 */public class GenericDemo4 { public static void main(String[] args) { //定義數組 String[] arr={"hello","world","java"}; Integer[] arr2={10,20,30}; //調用自定義函數分別打印數組 /*printArray(arr); printArray(arr2);*/ printArray2(arr);//傳遞String[]類型的數組的時候,T就變成了String類型 printArray2(arr2);//傳遞Integer[]類型的數組的時候,T就變成了Integer類型 /* * 上述做法可以定義兩個函數來遍歷不同數據類型的數組,這兩個函數以函數重載的形式存在,但是相對 * 來說比較麻煩,如果定義不同類型的數組,都會定義一個相對應的函數,太麻煩,這裡我們可以藉助 * 泛型方法來簡化代碼開發 */ } /* * 由於要打印不同類型的數組,所以這裡參數列表的類型不確定了,既然參數列表類型不確定了,我們可以使用 * 泛型 在函數返回值類型前面還得定義相應的泛型 */ public staticvoid printArray2(T[] arr) { /*//使用for循環遍歷數組 for (int i = 0; i < arr.length; i++) { System.out.print(arr[i]+" "); }*/ for (T t : arr) { System.out.print(t+" "); } //換行 System.out.println(""); } /*//遍歷整數 public static void printArray(Integer[] arr2) { //使用for循環遍歷數組 for (int i = 0; i < arr2.length; i++) { System.out.print(arr2[i]+" "); } } //遍歷字符串 public static void printArray(String[] arr) { //使用for循環遍歷數組 for (int i = 0; i < arr.length; i++) { System.out.print(arr[i]+" "); } //換行 System.out.println(""); }*/} /<code>
說明:因為參數中的數組類型不確定,遍歷時候的數據類型也不確定,所以都用泛型T來代替。
總結:1)自定義泛型方法格式:** 修飾符 返回值 函數名(參數列表 ){}**2)自定義泛型方法,泛型必須在函數返回值之前和函數修飾之後定義,否則報錯;3)泛型方法中泛型的確定:在方法被調用的時候,傳遞參數的時候才確定;
注意事項:靜態函數上的泛型:靜態函數不能使用類上定義的泛型。因為靜態方法的運行是不需要對象的,而類上的泛型必須在創建這個類對象的時候才能明確具體是什麼類型。而靜態函數運行的時候是沒有對象的,也就是說類上的泛型在靜態函數運行的時候還不知道是什麼類型。如果一個靜態方法,也需要泛型,請使用自定義泛型方法。
靜態函數的使用注意事項代碼演示如下:
1.4、泛型接口和泛型傳遞(掌握)
通過查閱API得知,類支持泛型,那麼接口也可以支持泛型,比如集合中的接口:接口Collection
那麼既然API中的接口支持泛型,自己定義的接口同樣也可以使用泛型。
泛型接口的格式:修飾符 interface 接口名{}
問題:泛型類的泛型,在創建類的對象時確定。那麼接口又無法創建對象,什麼時候確定泛型的類型呢?有兩種方式可以實現。
方式1:類實現接口的時候,直接明確泛型類型。
源代碼中的String類的的實現:
方式2:類實現接口的時候,還不確定數據類型,這時可以在實現類上隨便先定義個泛型,當這個類被創建對象的時候,
就明確了類上的泛型,於是接口上的泛型也明確了。我們管方式2這種方式叫做泛型的傳遞。
代碼實現如下:
舉例,API中集合的泛型使用情況解釋如下所示:
<code>比如:interface Collection{}interface List /<code>extends Collection {}class ArrayList implements List {}ArrayList<string> list = new ArrayList<string>();/<string>/<string>
結論:通過以上操作,上述集合接口中的泛型類型是String類型。
1.5、泛型通配符(掌握泛型中的通配符的使用)
需求:定義功能,打印集合中的對象。
分析和步驟:1)定義一個類GenericDemo6,在這個類中的主函數中創建ArrayList<string>集合的對象list;2)使用對象list調用add()函數向集合中添加幾個字符串數據;3)再創建一個HashSet<integer>集合類的對象set;4)使用對象set調用add()函數向集合中添加幾個整數數據;5)分別定義兩個函數來對上述的集合進行遍歷;/<integer>/<string>
上述定義了2個打印集合的方法,方法體中都是在使用迭代器遍歷集合。區別是方法上接收的集合類型不同,還有集合中保存的元素的數據類型不同。這樣使用迭代器遍歷的時候,迭代器的泛型需要根據集合中保存元素的具體的數據類型才能確定,其他的代碼書寫都相同。這樣會導致上述代碼重複冗餘,可以對上述代碼進行進一步的優化。
換句話說:通過觀察發現上述的兩個函數以函數重載的形式存在,幾乎一模一樣,還有泛型的數據類型不一致,還有集合的類型不一致,一個是ArrayList,另一個是HashSet,所以代碼冗餘,我們可以簡化代碼的開發,我們可以只定義一個函數來遍歷集合。既然兩個集合不一樣,我們這裡可以書寫集合的父類或者父接口Collection。由於集合中保存的數據類型也不一致,這裡也沒法寫,寫String 不行 Integer 也不可以。
說明:這裡書寫Object不可以,因為泛型格式要求兩側必須類型一致,這裡不一致了,會報錯Collection<object> coll=new ArrayList<string>()/<string>/<object>
所以這裡我們只能藉助泛型中通配符可以實現 : ?? 表示泛型的通配符,表示集合中的任意數據類型,傳遞過來的表示什麼數據類型,?就表示什麼數據類型
分析:現在需要定義一個方法既可以接收ArrayList,又可以接收HashSet集合容器對象,只能使用它們的父類或接口類型來接收,這樣就可以使用Collection接口類型接收。在寫方法的時候,如果要接收別人的數據,但是使用泛型不知道具體的數據類型,可以使用泛型的通配符 ? 來表示。? :表示的是任意的數據類型。當真正傳遞過來的集合中的數據是什麼類型,這個?就會自動的變成什麼類型。
完整代碼如下所示:
<code>package cn.xuexi.generic.demo1;import java.util.ArrayList;import java.util.Collection;import java.util.HashSet;import java.util.Iterator;/* * 需求:定義功能,打印集合中的對象。 */public class GenericDemo6 { public static void main(String[] args) { //創建ArrayList集合對象 ArrayList<string> list=new ArrayList<string>(); //向集合中添加數據 list.add("aaa"); list.add("ccc"); list.add("bbb"); list.add("ghfas"); //創建HashSet集合 HashSet<integer> set=new HashSet<integer>(); //向集合中添加數據 set.add(123); set.add(567); set.add(7843); set.add(45); //調用自定義函數分別遍歷上述兩個集合 printCollection(list); printCollection(set); } /* * 通過觀察發現以下的兩個函數以函數重載的形式存在,幾乎一模一樣,還有泛型的數據類型不一致, * 還有集合的類型不一致,一個是ArrayList,另一個是HashSet, * 所以代碼冗餘,我們可以簡化代碼的開發,我們可以只定義一個函數來遍歷集合 * 既然兩個集合不一樣,我們這裡可以書寫集合的父類或者父接口Collection * 由於集合中保存的數據類型也不一致,這裡也沒法寫,寫String 不行 Integer 也不可以 * 說明:這裡書寫Object不可以,因為泛型格式要求兩側必須類型一致,這裡不一致了,會報錯 * Collection<object> coll=new ArrayList<string>() * 所以這裡我們只能藉助泛型中通配符可以實現 : ? * ? 表示泛型的通配符,表示集合中的任意數據類型,傳遞過來的表示什麼數據類型,?就表示什麼數據類型 */ public static void printCollection(Collection> coll) { //迭代集合 for (Iterator> it = coll.iterator(); it.hasNext();) { System.out.println(it.next()); } } /*//自定義函數遍歷ArrayList函數 public static void printCollection(ArrayList<string> list) { //迭代集合 for (Iterator<string> it = list.iterator(); it.hasNext();) { String str = it.next(); System.out.println(str); } } //自定義函數遍歷HashSet函數 public static void printCollection(HashSet<integer> set) { for (Iterator<integer> it = set.iterator(); it.hasNext();) { Integer i= it.next(); System.out.println(i); } }*/}/<integer>/<integer>/<string>/<string>/<string>/<object>/<integer>/<integer>/<string>/<string>/<code>
注意:泛型的通配符雖然可以簡化代碼的開發,但是在開發中要慎用,因為如果使用通配符,那麼函數就可以接收任意的數據類型,這樣會導致代碼的不安全。
有的人會有疑問,我就是一個迭代遍歷有什麼不安全的,注意啦,我們在開發中可不是隻有遍歷這麼簡單,對接收的數據有可能進行其他的相關操作(增刪改),結果就會導致對任何數據都可以操作,這樣才會導致不安全。所以我們如果要想使用泛型的通配符那麼必須得使用通配符的限定。目的是考慮數據的安全性。
1.6、泛型限定(瞭解,能看懂即可)
泛型的限定:包括上限限定和下限限定。上限限定:在定義泛型的通配符的時候,如果需要對這個?號接收的類型進行限定,並且只知道具體的父類是什麼,而所有的子類都需要接收,這時就使用泛型的上限限定。上限限定的格式:? extends 父類類型或父接口類型例如:? extends Person :?代表的是一種類型,當前這個類型可以是Person本身,也可以是Person的子類。下限限定:在定義泛型的通配符的時候,如果需要對這個?號接收的類型進行限定,並且只知道當前的某個子類,而泛型需要接收的是當前的這個子類,或者子類的父類類型。可以使用泛型的下限限定格式:
? super 子類類型或實現類類型例如: ? super Student :?代表當前的類型可以是Student類型,也可以是Student的父類類型。但不能是Student 的子類,或者Student的兄弟。2、Map集合
2.1、Map集合介紹
2.1.1 為什麼要學習Map集合
Java中集合的關係圖如下圖所示:
說明:Collection接口下的所有集合中保存的對象都是孤立的。對象和對象之間並沒有任何關係存在。在生活中對象和對象之間必然會一定的聯繫存在。而我們學習的Collection接口下的所有子接口或者實現類(集合)它們中的確可以保存對象,但是沒有辦法維護這些對象之間的關係。而學習的Map集合,它也是存放對象的,但是可以對其中的對象進行關係的維護。
Map引入的圖解:需求:定義一個集合存儲班級學生的學生姓名。
補充:把Collection集合稱為單列集合。Map被稱為雙列集合。
2.1.2 Map集合的特點
特點:1)Map集合可以一次性存儲兩個對象;2)在Map集合中保存的key和value這樣的具備一定對應關係的一組(一對)數據,Map集合中存儲的是兩個對象的對應關係(映射關係)。[ key-value映射關係 ];3)Map集合中的key必須保證唯一(存儲的key元素不能重複,value可以重複,但是一個key只能對應一個value);4)Map集合中的key和value屬於一一對應關係(一個key只能對應一個value)
2.1.3 Map和Collection的區別
區別:1)Map中鍵唯一,值沒有要求。Collection中只有Set體系要求元素唯一;2)Map的數據結構針對鍵而言,Collection的數據結構針對元素而言;3)Map是雙列集合頂級接口,Collection是單列集合頂級接口,他們兩個分別是兩種集合的頂級接口,之間沒有必然的聯繫;
說明:Collection集合中只能存儲一個對象元素,稱為單列集合。Map集合中其實存儲的是兩個單列集合,稱為雙列集合。
2.2、Map集合中的方法(掌握)
1)增加元素:
在使用put存儲一對元素(key-value)對象時,會先拿key去判斷Map集合中是否已經存在。如果Map集合中沒有相同的key存在:就把key-value存儲到Map集合中,並返回null值。如果Map集合中有相同的key存在:會把之前存儲的value對象覆蓋。並返回之前的value對象(舊value對象)。這裡可以理解為修改value,但是不能修改key。
注意:由於Map是接口,不能創建對象,只能使用Map下面的子類HashMap或者TreeMap創建對象。
分析和步驟:1)創建集合HashMap<string>集合對象map,返回值類型是Map<string>;2)使用map對象調用put函數向集合中添加學生的學號作為key,姓名作為value;3)輸出對象map;/<string>/<string>
<code>package cn.xueximap.function.demo;import java.util.HashMap;import java.util.Map;/* * Map中的put函數的演示 * V put(K key, V value) 將指定的值與此映射中的指定鍵關聯(可選操作)。 */public class MapPutDemo { public static void main(String[] args) { // 創建集合對象 Map<string> map = new HashMap<string>(); //給集合中添加數據 map.put("001","張三"); map.put("002","李四"); map.put("003","王二"); map.put("004","麻子"); map.put("005","王五"); map.put("006","麻子"); String name = map.put("006","老麻子"); //輸出集合中的數據 System.out.println(map); System.out.println(name); }}/<string>/<string>/<code>
2)刪除元素:
清空集合。
remove是根據key刪除當前key對應的value這一組數據:如果Map集合中有與指定的key相同的元素存在:則刪除一對key-value對象,而不是隻刪除value,並返回刪除這組的value值;如果Map集合中沒有與指定的key相同的元素存在:沒有刪除操作,返回null;
問題:為什麼不可以通過value來刪除一組數據?因為key是唯一的,而value可以有多個,所以不能通過value來刪除一組數據,只能通過key值進行刪除。
分析和步驟:1)創建集合HashMap<string>集合對象map,返回值類型是Map<string>;2)使用map對象調用put函數向集合中添加學生的學號作為key,姓名作為value;3)使用map對象調用remove函數根據鍵key=004進行刪除鍵值對,並使用String類型接收返回值value4)輸出對象map和刪除的返回值value;5)使用對象map調用clear()函數清除Map集合中的元素數據;/<string>/<string>
<code>package cn.xuexi.map.function.demo;import java.util.HashMap;import java.util.Map;/* * Map中的remove函數的演示 * V remove(Object key) 如果存在一個鍵的映射關係,則將其從此映射中移除(可選操作)。 */public class MapRemoveDemo { public static void main(String[] args) { // 創建集合對象 Map<string> map = new HashMap<string>(); //給集合中添加數據 map.put("001","張三"); map.put("002","李四"); map.put("003","王二"); map.put("004","麻子"); map.put("005","王五"); map.put("006","麻子"); //調用remove函數刪除key為004的鍵值對組合 String value = map.remove("004");//返回刪除key為004的value值麻子 //輸出集合中的數據 System.out.println(map); System.out.println(value); //調用clear()函數清空map集合 //注意清空指的是將map集合中的所有元素清空,集合還在,還可以使用集合對象向集合中添加數據 map.clear(); System.out.println(map); map.put("009", "黑旋風"); System.out.println(map); }}/<string>/<string>/<code>
3)改變集合中的元素:使用put函數就可以根據集合的key改變集合中的value值。4)獲取集合中的元素:
根據指定的key元素對象,去 Map集合獲取相應的value對象。如果Map集合中沒有指定的key元素存在,則返回null。
注意:獲取也只能根據key獲取value,不能通過value獲取key。
分析和步驟:1)創建集合HashMap<string>集合對象map,返回值類型是Map<string>;2)使用map對象調用put函數向集合中添加學生的學號作為key,姓名作為value;3)使用map對象調用get函數根據鍵key=003獲取value值,並使用String類型接收返回值value;4)使用map對象調用get函數根據鍵key=007獲取value值,並使用String類型接收返回值value1;5)輸出對象map和獲得的value、value1;/<string>/<string>
<code>package cn.xueximap.function.demo;import java.util.HashMap;import java.util.Map;/* * Map中的get函數的演示 * V get(Object key) 返回指定鍵所映射的值;如果此映射不包含該鍵的映射關係,則返回 null。 */public class MapGetDemo { public static void main(String[] args) { // 創建集合對象 Map<string> map = new HashMap<string>(); //給集合中添加數據 map.put("001","張三"); map.put("002","李四"); map.put("003","王二"); map.put("004","麻子"); map.put("005","王五"); map.put("006","麻子"); //通過集合對象調用get函數根據key獲取value值 String value = map.get("003"); String value1 = map.get("007"); //輸出集合中的數據 System.out.println(map); System.out.println(value); //由於集合中沒有key為007的數據,所以返回null System.out.println(value1); }}/<string>/<string>/<code>
5)判斷方法:
boolean containsKey(Object key) 判斷Map集合中是否包含指定的key元素存在,包含返回true,否則返回false;boolean containsValue(Object value) 判斷Map集合中是否包含指定的value元素存在,包含返回true,否則返回false;
判斷集合是否為空,集合中沒有元素返回true,有元素返回false;
分析和步驟:1)創建集合HashMap<string>集合對象map,返回值類型是Map<string>;2)使用map對象調用put函數向集合中添加學生的學號作為key,姓名作為value;3)使用map對象調用containsKey()函數根據鍵key=002來判斷map是否含有002這個鍵,並使用boolean類型接收返回值boo,並輸出boo;4)使用map對象調用containsValue()函數根據值value=”田七”來判斷map是否含有”田七”這個值,並使用boolean類型接收返回值boo1,並輸出boo1;5)map調用clear()函數清空集合;6)map調用isEmpty()函數判斷集合是否為空,為空返回true,否則返回false;/<string>/<string>
<code>package cn.xuexi.map.function.demo;import java.util.HashMap;import java.util.Map;/* * Map中的判斷函數講解 */public class MapBooleanDemo { public static void main(String[] args) { // 創建集合對象 Map<string> map = new HashMap<string>(); //給集合中添加數據 map.put("001","張三"); map.put("002","李四"); map.put("003","王二"); map.put("004","麻子"); map.put("005","王五"); map.put("006","麻子"); //判斷集合中是否包含指定的key值 boolean boo = map.containsKey("002"); System.out.println(boo); //判斷集合中是否包含指定的value值 boolean boo1 = map.containsValue("田七"); System.out.println(boo1); //清除集合 map.clear(); //判斷集合是否為空 集合中沒有元素返回true,由元素返回false boolean boo2 = map.isEmpty(); System.out.println(boo2); }}/<string>/<string>/<code>
6)其他方法:
size() 獲取Map集合中存儲的key-value對應關係的個數。獲取集合長度。
Set
Collection
分析和步驟:
1)創建集合HashMap<string>集合對象map,返回值類型是Map<string>;/<string>/<string>
2)使用map對象調用put函數向集合中添加學生的學號作為key,姓名作為value;
3)使用map對象調用size()函數獲取map集合中鍵值對個數,並輸出結果;
4)使用map對象調用values()函數獲取map集合中value值的個數,使用Collection集合進行接收並遍歷輸出結果;
5)使用map對象調用keySet()函數獲取map集合中key值的個數,使用Set集合進行接收並遍歷輸出結果;
<code>package cn.xuexi.map.function.demo;import java.util.Collection;import java.util.HashMap;import java.util.Map;import java.util.Set;/* * Map中的其他函數講解 */public class MapOtherFunctionDemo { public static void main(String[] args) { // 創建集合對象 Map<string> map = new HashMap<string>(); //給集合中添加數據 map.put("001","張三"); map.put("002","李四"); map.put("003","王二"); map.put("004","麻子"); map.put("005","王五"); map.put("006","麻子"); //返回map集合中的鍵值對的個數 int size = map.size(); System.out.println(size); //獲取map集合中value值 Collection<string> values = map.values(); //遍歷集合 for (String value : values) { System.out.println(value); } //獲取map集合中的所有鍵集合 Set<string> keys = map.keySet(); //遍歷set集合 for (String key : keys) { System.out.println(key); } }}/<string>/<string>/<string>/<string>/<code>
2.3、Map集合的遍歷
通過前面的學習我們已經知道,針對Collection集合,它的遍歷可以使用Iterator迭代器進行遍歷。但是Map集合不能直接使用Iterator迭代器來遍歷,因為在Map集合根本就沒有提供獲得迭代器對象的函數。既然不能通過Iterator迭代器直接來遍歷,那是否可以間接使用Iterator迭代器來遍歷Map集合呢?之前講Map集合時,Map集合是用來存儲一對key-value兩個對象,既然存儲的是兩個對象,那麼能不能只獲取其中一個所有的對象?可以。Map集合屬於雙列集合,裡面有兩個單列集合。由於Map集合中的key是唯一的,所以我們我可以先獲取Map集合中的key,然後根據key值來獲取Map集合中的value值。
問題1:Map中的key對象,應該使用哪個集合存儲?key必須保證唯一性(不能重複),使用Set集合存儲。
問題2:如何將Map中的key存儲到Set集合呢?可以使用Map中的keySet方法:獲取Map集合中所有的key對象並存儲到Set集合中。
這樣通過上述操作就可以將Map集合中的key存放到Collection集合下面的set中,然後使用Iterator遍歷Map集合中的key所在的Set集合,進而可以使用
Map集合中的
通過key間接的獲取每個value。
注意:Map接口中提供了2個方法可以獲取到Map中的key 或者key和value關係對象
keySet():Map中的key存儲到Set集合中。
entrySet():Map中的key和value關係對象存儲到Set集合中。
注:由於Map中key是唯一的,不能重複的,所以Map集合中鍵值對整體也是不能重複的,但是單獨value值是可以重複的。
2.3.1、使用keySet方法來遍歷Map集合(根據鍵來遍歷)必須掌握
使用keySet方法來遍歷集合的圖解如下圖所示:
]
代碼如下所示:
需求:Map的遍歷方式1:keySet遍歷向Map集合中存儲幾個key-value對象,即夫妻鍵值對。
分析:A:找到所有丈夫的集合B:讓丈夫一個一個出來C:讓丈夫去找老婆
思路:A:找到所有鍵的集合:keySet()B:循環遍歷,取出每個鍵C:根據鍵找值:get(Object key)
分析和步驟:1)創建Map集合對象map;2)使用集合對象map調用put函數向集合中添加幾個數據,丈夫作為key,妻子作為value;3)使用集合對象map調用keySet函數獲取Map集合中所有的key,把所有的key保存到Set集合中,並獲取對象set;4)使用迭代器Iterator來對Set集合中的key進行迭代,使用迭代器對象it調用next()函數來獲取key值;5)然後使用Map集合的對象map調用get()函數,迭代的key值作為參數獲得key值對應的value,並輸出打印key和value值;
<code>package cn.xuexi.map.iterator.demo;import java.util.HashMap;import java.util.Map;import java.util.Iterator;import java.util.Set;/* * 使用keySet函數遍歷Map集合 */public class MapKeySetDemo { public static void main(String[] args) { // 創建集合對象 Map<string> map = new HashMap<string>(); //向集合中添加數據 map.put("李晨","范冰冰"); map.put("鄧超","孫儷"); map.put("文章","馬伊琍"); map.put("汪峰","章子怡"); /* * 通過Map的對象調用keySet函數獲得Map中的key值並保存到Set集合 * 所有的key鍵都保存到以下的set集合中了 */ Set<string> keys = map.keySet(); //使用迭代器迭代Set集合 for (Iterator<string> it = keys.iterator(); it.hasNext();) { //分別取出每個key值 String key = it.next(); //使用Map的對象調用get函數根據key獲得value String value = map.get(key); //輸出key和value System.out.println(key+"===="+value); } }}/<string>/<string>/<string>/<string>/<code>
2.3.2、使用entrySet遍歷(會使用即可,開發使用的較少)
在Map集合中提供的entrySet方法,它可以獲取到當前Map集合中的key和value的對應關係對象(映射對象)。
在Map集合中把key和value看成一組數據,然後Java中把這一組數據又一次封裝成了一個新的對象,這個對象就是key和value的對應關係對象。然後把這些對象保存到了Set集合中。Set集合中保存的是key和value對應關係對象。
說明:
Set集合中保存的是key和value對應關係對象屬於Map.Entry類型。
注意:通過查閱API得知Map.Entry類型表示在Map接口中還有一個內部接口Entry。而在內部接口Entry中有如下方法:
1)getKey()方法表示可以通過Map.Entry類型的對象調用此函數來獲得在Set集合中保存的是key和value對應關係對象中的key值;2)getValue()方法表示可以通過Map.Entry類型的對象調用此函數來獲得在Set集合中保存的是key和value對應關係對象中的value值;3)setValue()方法表示可以通過Map.Entry類型的對象調用此函數來修改在Set集合中保存的是key和value對應關係對象中的value值;使用Map集合中的entrySet()函數遍歷集合的過程圖解如下圖所示:
代碼實現如下所示:需求:演示:Map的遍歷方式2:entrySet遍歷。向Map集合中存儲幾個key-value對象,即夫妻鍵值對。
分析:
A:首先拿到所有夫妻的結婚證集合
B:取出每個結婚證
C:從結婚證中拿到丈夫和妻子
問題:結婚證是什麼呢?Map中存儲的元素,其實是成對的鍵值對數據。結婚證就是 一個鍵值對 對象。每一個鍵值對對象中有一個鍵和一個值。
思路:
A:獲取所有的鍵值對對象的集合
B:循環遍歷,拿到每個鍵值對對象
C:從鍵值對對象中取出鍵和值
問題:如何獲取鍵值對對象?鍵值對對象是個什麼類型呢?Set<map.entry>> entrySet() 返回此映射中包含的 鍵值對對象 的 Set集合。Map.Entry
分析和步驟:
1)創建Map集合對象map;
2)使用集合對象map調用put函數向集合中添加幾個數據,丈夫作為key,妻子作為value;
3)使用集合對象map調用entrySet函數獲取Map集合中所有的key和value對應關係的對象,把所有的對應關係的對象保存到Set集合中,並獲取對象keyValues;
4)使用迭代器Iterator來對Set集合中的的對應關係的對象keyValues進行迭代,使用迭代器對象it調用next()函數來獲取單個獨立的key-value對應關係對象keyValue;
5)然後使用keyValue對象調用Map.Entry中的getKey()和getValue()函數來獲得每個對應關係對象中的key和value,最後輸出key和value值;
<code>package cn.xuexi.map.iterator.demo;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import java.util.Set;/* * 使用Map集合中的entrySet函數遍歷集合 */public class MapEntrySetDemo { public static void main(String[] args) { // 創建集合對象 Map<string> map = new HashMap<string>(); //向集合中添加數據 map.put("李晨","范冰冰"); map.put("鄧超","孫儷"); map.put("文章","馬伊琍"); map.put("汪峰","章子怡"); /* * 使用entrySet()函數獲得鍵值對對應關係的對象 * KeyValues表示鍵值的對應關係的對象 */ Set<map.entry>> keyValues = map.entrySet(); //迭代Set集合 /* * Iterator<map.entry>> 表示每次迭代出來的是Map.Entry類型, * 並且對應關係對象中的key和value都是String類型 */ /*for (Iterator<map.entry>> it = keyValues.iterator(); it.hasNext();) { Map.Entry<string> keyValue = it.next(); //keyValue表示每個獨立的key-value對應關係的對象,現在分別取出對應關係中的key和value String key = keyValue.getKey(); String value = keyValue.getValue(); //輸出key和value System.out.println(key+"---"+value); }*/ //使用foreach循環遍歷Set集合 for (Map.Entry<string> keyValue : keyValues) { /* * keyValue表示單個獨立的映射關係對象,現在分別取出對應關係中的key和value */ String key = keyValue.getKey(); String value = keyValue.getValue(); //輸出key和value System.out.println(key+"。。。。"+value); } }}/<string>/<string>/<map.entry>/<map.entry>/<map.entry>/<string>/<string>/<code>
閱讀更多 瀟灑的程序員 的文章