Java集合框架讲解【泛型、Collection接口、Map接口、以及子接口和实现类、集合的遍历形式等】
文章目錄
- Collection集合框架體系
- 集合
- 一、List集合(interface)
- 1.ArrayList實現類(class)
- 2.LinkedList實現類(class)
- 3.二者區別(底層理解)
- 二、Set集合(interface)
- 1.HashSet實現類(class)
- HashSet的底層理解:
- 2.TreeSet實現類(class)
- 三、遍歷
- 1.傳統for循環
- 2.高級for循環
- 3.lambda表達式
- 4.迭代器
- 5.lambda表達式遍歷迭代器
- Map集合(interface)
- 1.HashMap實現類
- 2.TreeMap實現類
- 3.Map集合的遍歷
- (1)高級for循環,結合entries實現遍歷(針對鍵值都需要的情況)
- (2)for-each循環(只針對Key或者Value)
- (3)迭代器遍歷 Iterator
- (4)通過Key找Value遍歷
- 泛型(集合框架的規范)
- 簡介
下圖是本文所講述的整個Java集合框架基本內容,共分為倆大部分,Collection接口和Map接口
Collection集合框架體系
集合
概念
對象的容器,實現了對對象常用的操作,類似數組功能。
集合和數組的區別
- 1.數組的長度是固定的,集合長度不固定
- 2.數組可以儲存基本類型和引用類型,集合只能儲存引用類型
- 3.數組的長度是固定的,一旦數據量超出容量,則不可繼續儲存數據,但是對于集合來說,當數據量超過容量的時候,集合會自動擴容,舒服了~~~
一、List集合(interface)
List實現了Collection接口,它具有倆個常用的實現類:ArrayList類和LinkedList類。
1.ArrayList實現類(class)
Java API文檔
ArrayList實現類除了包含Collection接口中的所有方法之外,還包括List接口中提供的一些常用方法。
如下表:
| E get(int index) | 獲取此集合中指定索引位置的元素,E 為集合中元素的數據類型 |
| int index(Object o) | 返回此集合中第一次出現指定元素的索引,如果此集合不包含該元素,則返回 -1 |
| int lastIndexOf(Object o) | 返回此集合中最后一次出現指定元素的索引,如果此集合不包含該元素,則返回 -1 |
| E set(int index, Eelement) | 將此集合中指定索引位置的元素修改為 element 參數指定的對象。此方法返回此集合中指定索引位置的原元素 |
| List subList(int fromlndex, int tolndex) | 返回一個新的集合,新集合中包含起始索引到末尾索引之間的所有元素,包前不包后 |
常用操作:增刪改查
public class Demo02 {public static void main(String[] args) {List<String> aList = new ArrayList<String>();aList.add("shuyv2019");aList.add("shuyv2020");aList.add("shuyv2021");System.out.println(aList);List<Integer> bList = new ArrayList<Integer>();bList.add(2019);bList.add(2020);bList.add(2021);System.out.println(bList);//刪除集合中指定下標處的數據aList.remove(1);//aList.remove("shuyv2019");aList.forEach(temp->{System.out.println(temp);});//根據內容刪除Object o = 2020;bList.remove(o);for (Integer temp : bList) {System.out.println(temp);}//清空集合中的所有元素//aList.clear();//bList.clear();//修改集合中的元素aList.set(0,"凌2019");aList.forEach(temp->{System.out.println(temp);});} }注意上述代碼中的刪除操作,remove刪除有倆種方式,一種是根據索引進行刪除(int),另一種是直接根據內容刪除(Object)。
2.LinkedList實現類(class)
由上述圖片所描述的Collection集合框架體系可知,Link集合接口繼承了Collection接口,所以說LinkedList實現類包含Collection接口和List接口的所有方法,除此之外,LinkedList實現類當中還包含一些特別的方法。
如下表:
| void addFirst(E e) | 將指定元素添加到此集合的開頭 |
| void addLast(E e) | 將指定元素添加到此集合的末尾 |
| E getFirst() | 返回此集合的第一個元素 |
| E getLast() | 返回此集合的最后一個元素 |
| E removeFirst() | 刪除此集合中的第一個元素 |
| E removeLast() | 刪除此集合中的最后一個元素 |
代碼演示:
public class Demo01 {public static void main(String[] args) {// 創建集合對象LinkedList<String> products = new LinkedList<String>();String str1 = new String("shuyv2019");String str2 = new String("shuyv2020");String str3 = new String("shuyv2021");String str4 = new String("shuyv2022");products.add(str1);products.add(str2);products.add(str3);products.add(str4);System.out.println(products);//在集合末尾添加元素String str5 = new String("shuyv2023");products.addFirst(str5);System.out.println(products);//返回集合的第一個元素String the_first = products.getFirst();System.out.println(the_first);} }3.二者區別(底層理解)
ArrayList類和LinkedList類都是List集合接口的實現類,因此都實現了List的所有未實現方法,只是實現方式不同。
此二者最大的區別,則是底層儲存數據的方式不同,ArrayList是基于順序表數據結構而實現,訪問速度快。LinkedList是基于鏈表數據結構而實現,占用內存較大,適合批量插入或者刪除數據。
二、Set集合(interface)
- Set集合當中的對象不按照特定的方式排序。
- Set集合中不能包含重復的對象,并且最多只允許包含一個null元素。
- Set集合實現了Collection接口,它主要有倆個常用的實現類:HashSet和TreeSet
1.HashSet實現類(class)
顧名思義,HashSet集合底層是按照Hash算法來儲存集合中的元素。因此具有良好的存取和查找性能。
HashSet具有以下特點:
- 1.不能保證元素的排列順序,順序可能與添加順序不同,順序也有可能發生變化。
- 2.HashSet不是同步的,如果多個線程同時訪問或者修改一個HashSet,則必須通過代碼來保證q其同步。
- 3.集合元素值可以是null。
- 4.具有很好的存取和查找性能。
代碼演示:
public class Demo01 {public static void main(String[] args) {HashSet hashSet = new HashSet();String str1 = new String("shuyv2019");String str2 = new String("shuyv2020");String str3 = new String("shuyv2021");String str4 = new String("shuyv2022");String str5 = new String("shuyv2022");hashSet.add(str1);hashSet.add(str2);hashSet.add(str3);hashSet.add(str4);hashSet.add(str5);System.out.println("2019-2022年的shuyv:" + hashSet);Iterator<String> it = hashSet.iterator();while (it.hasNext()) {System.out.println((String) it.next());}System.out.println(hashSet.size());} }執行結果如下:
2019-2022年的shuyv:[shuyv2019, shuyv2020, shuyv2022, shuyv2021] shuyv2019 shuyv2020 shuyv2022 shuyv2021 4通過上述代碼可知,如果向Set集合中添加倆個相同的元素,則后添加的元素會覆蓋前面添加的元素,即在Set集合中不會出現相同的元素。
HashSet的底層理解:
當我們向HashSet存入一個元素的時候,HashSet會調用該對象的hashCode()方法來獲取該對象的hashCode值(十六進制哈希值,也就是內存地址值),然后根據該hashCode值決定該對象在HashSet中的存儲位置。所以要特別注意一點,雖然HashSet中不能出現重復的元素,但是也有特殊情況,比如當使用equals()方法來比較倆個元素時,如果返回值為true,但是這倆個元素的hashCode不相等,HashSet會把這倆個元素放在不同的位置,依然可以添加成功。
2.TreeSet實現類(class)
TreeSet類同時實現了Set接口和SortedSet接口。SortedSet接口是Set接口的子接口,可以實現對集合進行字然排序,因此使用TreeSet類實現的Set接口默認情況下是自然排序的,這里的自然排序是指升序。
這里的自然排序也有局限性,因為*TreeSet只能對實現了Comparable接口的類對象進行排序*。
Comparable接口請查詢Java API文檔進行了解
Java API文檔
TreeSet實現類除了實現Collection接口所有的方法之外,還提供了一些常用方法。
如下表:
| E first() | 返回此集合中的第一個元素。其中,E 表示集合中元素的數據類型 |
| E last() | 返回此集合中的最后一個元素 |
| E poolFirst() | 獲取并移除此集合中的第一個元素 |
| E poolLast() | 獲取并移除此集合中的最后一個元素 |
| SortedSet subSet(E fromElement,E toElement) | 返回一個新的集合,新集合包含原集合中 fromElement 對象與 toElement。。對象之間的所有對象。包含 fromElement 對象,不包含 toElement 對象 |
| SortedSet headSet<E toElement〉 | 返回一個新的集合,新集合包含原集合中 toElement 對象之前的所有對象。不包含 toElement 對象 |
| SortedSet tailSet(E fromElement) | 返回一個新的集合,新集合包含原集合中 fromElement 對象之后的所有對象。包含 fromElement 對象 |
注意:方法看上去多一些,但其實只是一些簡單的集合元素獲取,還有截取,注意索引范圍。
代碼舉例:
public class Demo02 {public static void main(String[] args) {TreeSet<Double> treeSet = new TreeSet<Double>();Double num1 = 2020.0;Double num2 = 2019.0;Double num3 = 2021.0;Double num4 = 2022.0;Double num5 = 2022.0;treeSet.add(num1);treeSet.add(num2);treeSet.add(num3);treeSet.add(num4);treeSet.add(num5);System.out.println("treeSet中的元素:" + treeSet);//返回集合中的第一個元素和最后一個元素System.out.println(treeSet.first());System.out.println(treeSet.last());//集合截取Object newSet = treeSet.subSet(2020.0,2022.0);System.out.println(newSet);Iterator<Double> it = treeSet.iterator();while (it.hasNext()) {System.out.println(it.next());}} }三、遍歷
1.傳統for循環
傳統的for循環,就是最普通最簡單的形式,如下代碼舉例:
for (int i = 0; i < aList.size(); i++) {System.out.println(aList.get(i)); }2.高級for循環
語法格式:
for(數據類型 變量名 : 集合/數組) {代碼塊 };注意:在高級for循環中定義的變量,每次循環都會被集合中的元素賦值,也就是說,該變量接受的是集合中的每個元素。
代碼演示:
for (Object temp : aList) {System.out.println(temp); }3.lambda表達式
匿名函數,是在高級for循環的基礎上,再次簡化語法。
語法格式如下:
集合.forEach(臨時變量->{代碼塊 });代碼演示:
aList.forEach(temp->{System.out.println(temp); });注意:
- 1.在使用lambda表達式的時候,不需要指定數據類型,它會自動識別。
- 2.lambda表達式只針對集合,不可以遍歷數組。
4.迭代器
Iterator(迭代器)是一個接口,它的作用就是遍歷容器內的所有元素,迭代器不同于Collection和Map系列的集合,Collection和Map系列集合主要是用于盛裝其他對象,而Iterator則主要用于遍歷訪問Collection中的元素。
Iterator接口中定義的方法:
| boolean hasNext() | 如果被迭代的集合沒有被遍歷完,則返回true |
| Object next() | 返回集合里的下一個元素 |
| void remove() | 刪除集合里上一次next方法返回的元素 |
| void forEachRemaining(Consumer action) | 這是Java8當中新增的默認方法,該方法可使用Lambda表達式來遍歷集合元素 |
代碼演示:
public class IteratorTest {public static void main(String[] args) {// 創建一個集合,多態語法(基于繼承)Collection the_Set = new HashSet();the_Set.add("shuyv2019");the_Set.add("shuyv2020");the_Set.add("shuyv2020");the_Set.add("shuyv2021");the_Set.add("shuyv2022");System.out.println(the_Set);// 調用forEach()方法遍歷集合,,注:lambda表達式System.out.println("使用lambda表達式遍歷結果如下:");the_Set.forEach(temp->{System.out.println(temp);});System.out.println("-----------------------------------");System.out.println("使用迭代器遍歷結果如下:");// 迭代器遍歷Iterator it = the_Set.iterator(); // 獲取迭代器對象itwhile (it.hasNext()) {// it.next()返回的數據類型是Object類型,因此需要強制類型轉換String obj = (String) it.next();System.out.println(obj);if (obj.equals("shuyv2020")) {// 從集合中刪除上一次next()方法返回的元素it.remove();}}System.out.println("------------------------迭代過程中刪除了shuyv2020,集合結果如下:");System.out.println(the_Set);} }代碼執行結果如下:
[shuyv2019, shuyv2020, shuyv2022, shuyv2021] 使用lambda表達式遍歷結果如下: shuyv2019 shuyv2020 shuyv2022 shuyv2021 ----------------------------------- 使用迭代器遍歷結果如下: shuyv2019 shuyv2020 shuyv2022 shuyv2021 ------------------------迭代過程中刪除了shuyv2020,集合結果如下: [shuyv2019, shuyv2022, shuyv2021]注意事項:
Iterator(迭代器)必須依附于Collection對象,如若有一個Iterator對象,那么必然有一個Collection對象。
當使用Iterator(迭代器)訪問Collection集合元素的時候,Collection集合里的元素不能改變,只有通過Iterator中的remove()方法刪除上一次next()方法返回的集合元素才可以,否則會引發“java.util.ConcurrentModificationException”異常
5.lambda表達式遍歷迭代器
根據3、4小節直接通過代碼展示
public class Demo02 {public static void main(String[] args) {// 創建一個集合Collection objs = new HashSet();objs.add("shuyv2019");objs.add("shuyv2020");objs.add("shuyv2021");// 獲取objs集合對應的迭代器Iterator it = objs.iterator();// 使用lambda表達式遍歷迭代器it.forEachRemaining(temp->{System.out.println("迭代集合元素:" + temp);});} }運行結果如下
迭代集合元素:shuyv2019 迭代集合元素:shuyv2020 迭代集合元素:shuyv2021Map集合(interface)
Map是一種鍵值對(key-value)集合,Map集合中的每一個元素都包含一個鍵(key)對象和一個值(value)對象。Map集合用于保存具有映射關系的數據。
注意:
- 1.Map結合中的key和value都可以是任何引用數據類型。
- 2.Map中的key不允許重復,value可以重復。而且使用equals方法來比較key的時候返回值永遠是false。
- 3.key和value一一對應,通過key來訪問value。
Map結合接口主要有來個實現類:HashMap類和TreeMap類。
HashMap類底層由哈希算法來存取鍵對象,TreeMap類可以對鍵對象進行排序。
Java API文檔
1.HashMap實現類
以下表格是一些常用方法
| void clear() | 刪除該 Map 對象中的所有 key-value 對。 |
| boolean containsKey(Object key) | 查詢 Map 中是否包含指定的 key,如果包含則返回 true。 |
| boolean containsValue(Object value) | 查詢 Map 中是否包含一個或多個 value,如果包含則返回 true。 |
| V get(Object key) | 返回 Map 集合中指定鍵對象所對應的值。V 表示值的數據類型。通過鍵獲取值 |
| V put(K key, V value) | 向 Map 集合中添加鍵-值對,如果當前 Map 中已有一個與該 key 相等的 key-value 對,則新的 key-value 對會覆蓋原來的 key-value 對。 |
| void putAll(Map m) | 將指定 Map 中的 key-value 對復制到本 Map 中。 |
| V remove(Object key) | 從 Map 集合中刪除 key 對應的鍵-值對,返回 key 對應的 value,如果該 key 不存在,則返回 null |
| boolean remove(Object key, Object value) | 這是 Java 8 新增的方法,刪除指定 key、value 所對應的 key-value 對。如果從該 Map 中成功地刪除該 key-value 對,該方法返回 true,否則返回 false。 |
| Set entrySet() | 返回 Map 集合中所有鍵-值對的 Set 集合,此 Set 集合中元素的數據類型為 Map.Entry |
| Set keySet() | 返回 Map 集合中所有鍵對象的 Set 集合 |
| boolean isEmpty() | 查詢該 Map 是否為空(即不包含任何 key-value 對),如果為空則返回 true。 |
| int size() | 返回該 Map 里 key-value 對的個數 |
| Collection values() | 返回該 Map 里所有 value 組成的 Collection |
案例演示:
創建HashMap集合用來保存NBA球員信息,然后通過上述表格的常用方法對集合進行操作。
Scanner輸入:Durant
執行結果如下
2.TreeMap實現類
TreeMap使用的方法和HashMap相同,唯一的不同就是,TreeMap可以對鍵對象進行排序。
3.Map集合的遍歷
Map集合的遍歷和上文當中Collection中的遍歷方式沒有太大的區別。
(1)高級for循環,結合entries實現遍歷(針對鍵值都需要的情況)
高級for循環結合entries實現遍歷,這是最常見的方式,并且在大多數情況下也是最可取的遍歷方式。在鍵值都需要的時候使用。
public class Demo02 {public static void main(String[] args) {Map<String,String> map = new HashMap<String, String>();map.put("凌薇","2020");map.put("shuyv","2019");for (Map.Entry<String,String> entry : map.entrySet()) {String mapKey = entry.getKey();String mapValue = entry.getValue();System.out.println(mapKey + ":" + mapValue);}} }執行結果如下:
凌薇:2020 shuyv:2019(2)for-each循環(只針對Key或者Value)
使用for-each循環遍歷key或者values,一般只適用于只需要key或者values時使用。性能上比entrySet較好。
注意:這邊的for-each循環和lambda表達式forEach不一樣。
public class Demo03 {public static void main(String[] args) {Map<String,String> map = new HashMap<String, String>();map.put("凌薇","2020");map.put("shuyv","2019");// for循環打印輸出結合中的keyfor (String key : map.keySet()) {System.out.println(key);}// 打印值集合for (String value : map.values()) {System.out.println(value);}} }執行結果如下:
凌薇 shuyv 2020 2019(3)迭代器遍歷 Iterator
public class Demo04 {public static void main(String[] args) {Map<String, String> map = new HashMap<String, String>();map.put("凌薇","2020");map.put("shuyv","2019");Iterator<Map.Entry<String,String>> entries = map.entrySet().iterator();while (entries.hasNext()) {Map.Entry<String,String> entry = entries.next();String key = entry.getKey();String value = entry.getValue();System.out.println(key + ":" + value);}} }執行結果如下:
凌薇:2020 shuyv:2019(4)通過Key找Value遍歷
通過鍵找值遍歷,這種方式的效率比較低,因為本身從鍵去找值就是比較耗時的操作。
代碼演示如下
for(String key : map.keySet()){String value = map.get(key);System.out.println(key+":"+value); }泛型(集合框架的規范)
簡介
Java的集合有缺點,當把對象放進集合當中時,該集合不能夠記錄這個對象是什么類型的,所以設計者們把集合設計成能接受任何類型的對象,從而使集合更加靈活。但是,集合中的對象都被編譯成了Object類型(當然在運行過程中該對象的類型沒有改變)。
所以在使用集合的時候會出現下問題:
- 1.集合對元素類型沒有任何限制,這樣可能會引發一些問題,例如,當我們想創建一個保存Dog對象的集合,但程序也可以輕易的將Cat對象丟進去,所以引發異常。
- 2.由于把對象丟進集合當中時,集合丟失了對象的狀態信息,就是說集合不知道該對象的數據類型,直接認為該對象是Object類型,因此取出集合元素通常還需要強制類型轉換,這種強制類型轉換既增加了編譯的復雜程度,也容易引發ClassCastException異常。
所以為了解決該類問題,Java出現了泛型。泛型可以在編譯的時候檢查類型安全,并且所有的強制類型轉換都是自動的和隱式的,提高了代碼的重用率。
總結
以上是生活随笔為你收集整理的Java集合框架讲解【泛型、Collection接口、Map接口、以及子接口和实现类、集合的遍历形式等】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 利用java实现excel转pdf文件
- 下一篇: java8实战教程,[JAVA] 汪大神