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