呼~,歷過好幾天的奮戰終於把集合框架肝完了,b站某馬老師講的是真的非常詳細而且動聽,原理給你分析得明明白白的,此前也找了許多關於集合這一大章節的視頻,發現更多的是針對於使用,原理講的並不是很多,這就導致我在練習或者回顧時還是一知半解。以下是我結合視頻以及個人的一些理解和體會做的筆記總結。路漫漫其修遠兮,吾將上下而求索,希望這篇總結對你有些許幫助,嘻嘻!
1.1集合概述:
集合:Java中提供的一種容器,可以用來存儲多個數據。java集合大致可以分為Set,List,Queue和Map四種體系。
數組和集合的區別:
-
數組的長度是固定的。集合的長度是可變的。
-
數組存儲的是同一類型的數據,可以存儲基本數據類型值。容器能存儲對象,而且存儲對象的類型可以不一致。在開發中當對象多的時候,使用容器進行存儲。
1.2集合架構
單列集合體系結構:
Collection接口是所有單列集合的父接口,因此在單列集合中定義的List和set通用的一些方法,這些方法可以操作所有的單列集合。方法如下:
1.3Collection集合常用方法
-
public boolean add(E e); 向集合中添加元素
-
public boolean remove(E e); 刪除集合中的某個元素
-
public void clear(); 清空集合中所有的元素
-
public boolean contains(); 判斷集合中是否含有xxx元素
-
publicboolean isEmpty(); 判斷集合是否為空
-
publicint size(); 計算集合的長度
-
public Object[] toArray(); 將集合轉成一個數組
【參考代碼】
package Collection;
import java.util.ArrayList;
import java.util.Collection;
/*
Collection集合常用方法
boolean add(E e); 向集合中添加元素
boolean remove(E e); 刪除集合中的某個元素
void clear(); 清空集合中所有的元素
boolean contains(); 判斷集合中是否含有xxx元素
boolean isEmpty(); 判斷集合是否為空
int size(); 計算集合的長度
Object[] toArray(); 將集合轉成一個數組
*/
public class Test {
public static void main(String[] args) {
//創建集合對象 , 可以多態使用
Collection<String>col = new ArrayList<>();
// Collection<String>col = new HashSet<>(); 下面的功能照樣能實現:共性方法
col.add("小明"); // 添加元素
col.add("小紅");
col.add("小藍");
col.add("小綠");
System.out.println(col); //[小明, 小紅, 小藍, 小綠]
//boolean remove(E e); 刪除集合中的某個元素
// boolean ans = col.remove("小明");
// System.out.println(ans);//true
// System.out.println(col);//[小紅, 小藍, 小綠]
//void clear(); 清空集合中所有的元素
// col.clear();
// System.out.println(col);//[]
//boolean contains(); 判斷集合中是否含有xxx元素
// boolean result = col.contains("小明");
// System.out.println(result);//true
//boolean isEmpty(); 判斷集合是否為空
// boolean result = col.isEmpty();
// System.out.println(result);// 不為空false
//int size(); 計算集合的長度
// int len = col.size();
// System.out.println(len);// 4
//Object[] toArray(); 將集合轉成一個數組
Object[] arr = col.toArray();
// 遍歷數組
// for (int i = 0; i < arr.length; i++) {
// System.out.println(arr[i]);
// }
}
}
二:迭代器Iterator
引入:由於集合有多種,每種集合存儲跟讀取的方式都不一樣,好比衣櫃、水瓶、葯瓶,你存和取的方式肯定不一樣。如果每種集合都定義一種遍歷方式那將十分的繁瑣。
迭代器(Iterator):它不是一個容器而是接口,它是一種用於訪問容器的方法,可用於迭代 List、Set和Map等容器。
迭代:即Collection集合的通用獲取方式。再獲取元素之前先要判斷集合中是否有元素,如果有就將這個元素去取出來,繼續再判斷,直到集合所有元素被取出來為止。即:一個一個的往外拿。
作用:幫我們遍歷或者拿到容器里邊的數據。
2.1Iterator接口
迭代器常用操作:
-
next() 下一個
-
hasNext() 判斷是否存在下一個元素
-
remove() 刪除元素
迭代器的使用步驟:
-
使用集合中的的方法iterator()獲取迭代器的實現類對象,使用Iterator接口接收(多態)
-
使用Tterator接口中的方法hashnext()判斷還有沒有下一個元素
-
使用Tterator接口中的方法next()取出集合的下一個元素
【參考代碼】
package Iterator;
import javax.swing.text.html.parser.Entity;
import java.util.*;
public class Test {
public static void main(String[] args) {
//創建一個集合對象
Collection<String>col = new ArrayList();
//添加元素
col.add("小明");
col.add("小紅");
col.add("小藍");
col.add("小綠");
/*
1.使用集合的方法iterator()獲取迭代器的實現類對象,使用Iterator接口接收(多態)
注意:
Iterator接口也是有泛型的,迭代器的泛型跟集合走,集合是什么泛型,迭代器就是什么泛型
*/
// 多態 接口 實現類對象
Iterator<String>it = col.iterator();
// 2.使用 Iterator接口中的hashNext方法判斷是否還有下一個元素
while(it.hasNext());{
// 3.使用 Iterator接口中的next方法取出集合的下一個元素
String str = it.next();
System.out.println(str);
}
}
}
2.2Iterator的實現原理:
2.3增強for()
增強for循環(for each循環)是JDk1.5之后的一個高循環,專門用來遍歷數組和集合的,所有的數組跟單列集合都可以使用。它的內部原理就是一個迭代器Iterator,所以在遍歷過程中,不能對集合元素進行增刪操作。
語法:
for(類型 變量 : 數組/集合){// 數組或者集合里的每一項賦值給這個變量
// 循環體
}
【參考代碼】
String[] student = {"小明","小紅","小藍"};
// // 傳統遍歷方式
// for (int i = 0; i < student.length; i++) {
// System.out.println(student[i]);
// }
// 增強for
for(String c : student){
System.out.println(c);
}
--------------------------------
List<Integer>list = new ArrayList<Integer>();
list.add(123);
list.add(234);
list.add(456);
for(Integer n : list){
System.out.println(n);
}
注:增強for必須有被遍歷的目標。目標只能是數組或者Collection,而它僅僅作為遍歷操作實現
2.4迭代器注意事項
-
迭代器是一次性對象。我們不能重置迭代器,它不能被重用。
-
要再次遍歷同一集合的元素,請通過調用集合的iterator()方法來創建一個新的Iterator。
三:泛型
3.1泛型概述
在前面學習集合時,我們知道集合時可以存放任意對象的,只要把對象存儲集合后,它們都會被向上轉型提升為Object類型。當我們要取出這些對象時必須進行類型強制轉換,由Object類型變為原來的類型。
3.2泛型的優缺點
不使用泛型:
- 好處:集合默認類型是Object類,可以存儲任意類型的數據
- 弊端:不安全,會引發異常,需要強轉。
public static void main(String[] args) {
List list = new ArrayList();
list.add("小明");
list.add("小紅");
for (int i = 0; i < list.size(); i++) {
String s= (String)list.get(i) // 強轉
System.out.println(s);
}
}
使用泛型:
-
好處:避免了類型強制轉化的麻煩,存的什么類型,取出來的也是什么類型;代碼運行之后才會拋出異常,寫代碼時不會報錯
-
弊端:泛型是什么類型只能存儲什么類型的數據。
public static void main(String[] args) {
List<String> list = new ArrayList();// 規范了數據類型,只能放字符串!
list.add("小明");
list.add("小紅");
//stringList.add(123);// 除了字符串以外的類型不能加,報錯!
for (int i = 0; i < list.size(); i++) {
String s = list.get(i); // 不用再強轉了
System.out.println(s);
}
}
在上述的實例中,我們只能添加String類型的數據,否則編譯器會報錯。
3.3泛型的定義與使用
泛型類
定義格式:
修飾符 class 類名<泛型變量>{
}
// 注:泛型變量建議使用E、T、K、V
例如:
public class Box<T> {
private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
參考示例:
注:在創建對象時確定泛型的類型
泛型方法
定義格式:
修飾符 <泛型變量> 返回值的類型 方法名稱(形參列表){
//方法體
}
注:含有泛型的方法,在調用的時候確定泛型的數據類型
傳遞什么類型的參數,泛型就是什么類型
參考示例:
泛型接口
定義格式:
public interface 接口名<泛型類型> {
}
使用方式1:定義接口的實現類,實現接口,並且指定接口的泛型
使用方式2:接口使用什么泛型,實現類就使用什么泛型,類跟着接口走。
就相當於定義了一個含有泛型的類,創建對象的時候確定泛型的類型。
下圖接口同上圖接口
3.4泛型的通配符
當使用泛型類或接口時,傳遞數據中,泛型類型不確定,可以通過通配符表示<?>表示。但一旦使用泛型的通配符后,只能使用Object類中的共性方法,集合中元素自身方法無法使用。
通配符的基本使用
泛型的通配符:不知道使用什么類型來接收的時候,此時可以使用 ? ,?表示未知通配符
此時只能接收數據,不能往集合中存儲數據。
【參考代碼】
package FanXing;
import javax.swing.text.html.HTMLDocument;
import java.util.ArrayList;
import java.util.Iterator;
/*
泛型的通配符:
?:代表數據類型
使用方式:
不能在創建對象時使用
只能作為方法的傳遞參數使用
*/
public class Generic {
public static void main(String[] args) {
ArrayList<Integer>list01 = new ArrayList<>();
list01.add(123);
list01.add(456);
ArrayList<String>list02 = new ArrayList<>();
list02.add("小明");
list02.add("小紅");
// ......還有很多其它類型
printArray(list01);
printArray(list02);
/*
定義一個方法,能遍歷所有類型的ArrayList集合
這時候我們不知道ArrayList集合使用的是什么類型,可以使用泛型的通配符:?來代表數據類型
注意:泛型沒有繼承的概念
*/
}
public static void printArray(ArrayList<?>list){
// 使用迭代器遍歷集合
Iterator<?> it = list.iterator();
while(it.hasNext()){
Object obj = it.next();//it.next()取出的元素是Object類。Object類 可以接收任意的數據類型
System.out.println(obj);
}
}
}
通配符高級使用-----受限泛型
之前設置泛型的時候,實際上是可以可以任意設置的,只要是類就可以設置。但在Java的泛型中可以指定一個泛型的上限和下限。
泛型的上限:
-
格式:類型名稱<? extends E >對象名稱 代表的泛型只能是E類型的子類/本身
-
意義:只能接收該類型及其子集
泛型的下限:
-
格式:類型名稱<? super E >對象名稱 代表的泛型只能是E類型的父類/本身
-
意義:只能接收該類型及其父類
比如:Object類、String類、Number類、Integer類,其中Number類是Integer的父類。
四:Java常見數據結構
集合是基於數據結構做出來的,不同的集合底層采用不同的數據結構。不同的數據結構,功能和作用是不一樣的。
數據結構是指數據以什么方式組織在一起。不同的數據結構,增刪查的性能是不一樣的。
41棧
棧:stack,又稱堆棧,它是運算受限的線性表,只能在棧的受限一端進行插入和刪除操作。
特點:先進后出
4.2隊列
隊列:queue,簡稱隊,它同棧由於也是運算受限的線性表,只能在表的一端進行插入操作,而在表的另一端進行刪除操作。
特點:先進先出
4.3數組
數組:Array,是個有序的元素序列,數組在內存中開辟一段連續的空間。
特點:
-
查詢快:隨機存取,通過索引可以快速訪問元素
-
增刪慢:靜態分配內存,數組的長度是固定,存在空間閑置或者溢出現象;不適合進行插入和刪除操作,需要移動大量元素。
4.4鏈表
鏈表:linked list,由一系列結點node組成,結點可以在運行時動態產生。每個節點包含兩個部分:數據域(data)和指向下一個節點的指針域(next)。鏈表包括單鏈表和雙向鏈表。
-
單鏈表:鏈表中只有一條鏈子,不能保證元素的順序(存儲和取出的順序可能不一致)
-
雙向鏈表:鏈表中只有兩條鏈子,有一條鏈子專門記錄元素的順序,是一個有序的集合。
特點:
-
查詢慢:鏈表的地址不是連續的,每次查詢都要從頭到尾進行遍歷。
-
增刪快:動態分派內存,增/刪一個節點對於鏈表整體結構沒有影響,增刪操作效率高。
4.5紅黑樹
紅黑樹:R-B Tree,全稱是Red-Black Tree,又稱為“紅黑樹”,它一種特殊的二叉查找樹。紅黑樹的每個節點上都有存儲位表示節點的顏色,可以是紅(Red)或黑(Black),它是一種弱平衡二叉樹(Weak AVL)。
特點:
(1)每個節點或者是黑色,或者是紅色。 (2)根節點是黑色。 (3)每個葉子節點(NIL)是黑色。 [注意:這里葉子節點,是指為空(NIL或NULL)的葉子節點!] (4)如果一個節點是紅色的,則它的子節點必須是黑色的。 (5)從一個節點到該節點的子孫節點的所有路徑上包含相同數目的黑節點。
注:以上數據結構可以結合所學過c語言數據結構
五:List集合體系
5.1List概述
List集合體系:添加元素,是有序,可重復,有索引的,大小可變。實際開發中常用的是ArrayList集合。List集合體系包括以下幾種:
-
ArrayList——添加元素,是有序,可重復,有索引的。
-
LinkedList——添加元素,是有序,可重復,有索引的。
-
Vector——查詢快,增刪慢;運行效率慢、線程安全
List集合繼承了Collection集合的全部功能,同時因為List集合系列有索引,所以多了很多按照索引操作元素的方法:
add(int index, E element) 根據索引添加元素
get(int index) 根據索引獲取元素
remove(int index) 根據索引刪除元素
set(int index, E element) 根據索引修改該位置上的元素
contains(E element)判斷容器是否含有XXX東西
clear() 清空集合中的元素
size()計算集合的大小
【參考代碼】
package Collection;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class TestList {
public static void main(String[] args) {
List<String>list = new ArrayList();
// 換成Linkedist 下面的操作都能一樣實現
list.add("小明");
list.add("小紅");
list.add("小藍");
list.add("小綠");
list.add("小明");
// // 在某個索引位置往集合中添加元素
// list.add(2,"哈哈哈哈");
// System.out.println(list);
// // 刪除集合中某個元素
// list.remove("小藍");
// // 根據索引獲取元素
// System.out.println(list.get(0));
// // 修改索引位置處的元素
// list.set(0,"小明很明白!");
// System.out.println(list.get(0));//小明很明白!
// // 計算列表的大小(長度):
// System.out.println(list.size());
// //判斷列表中是否有xxx false
// System.out.println(list.contains("小藍"));
}
}
5.2List遍歷方式
-
for循環
// 遍歷列表
for (int i = 0; i < list.size(); i++) {
String str = list.get(i);
System.out.println(str);
} -
迭代器
Iterator<String>it = list.iterator(); // 創建一個List的迭代器
while(it.hasNext()){// 判斷有沒有下一個元素
String s = it.next();
System.out.println(s);
} -
增強for
List<String>list = new ArrayList<>();
for(String s : list){
System.out.println(s);
} -
Lambda表達式(了解)
list.foreach(s -> {
System.out.println(s);
});
5.3ArrayList集合
ArrayList集合存儲的結構是數組結構,元素增刪慢,查詢快。最常用。
5.4LinkedList集合
LinkedList集合存儲的結構是鏈表結構,方便元素的添加、刪除操作。LinkedList是一個雙向鏈表
LinkedList的特點:
-
底層是一個鏈表結構:查詢慢,增刪快
-
里邊含有大量操作首尾元素的方法
-
注:使用LinkedList集合特有的方法,不能使用多態,命名要注意了!
實際開發中對一個集合的添加、刪除操作經常涉及首尾操作,LinkedList提供了很多操作首尾元素方法
public void addFirst(E e); 將指定的元素插到列表開頭。
public void addLat(E e); 將指定的元素插到列表結尾。 此方法等效於add()方法
public void push(E e); 將元素推入此列表所示的堆棧。 此方法等效於addFirst()方法
public E getFirst(); 返回此列表的第一個元素
public E getLast(); 返回此列表的最后一個元素
public E removeFirst(); 移除並返回此列表的第一個元素
public E removeLast(); 移除並返回此列表的最后一個元素
public E pop(E e); 入此列表所示的堆棧中彈出一個元素。
public boolean isEmpty(); 如果列表為空 返回true
【參考代碼】
package Collection;
/*
public void addFirst(E e); 將指定的元素插到列表開頭。
public void addLast(E e); 將指定的元素插到列表結尾。
public void push(E e); 將元素推入此列表所示的堆棧。
public E getFrist(); 返回此列表的第一個元素
public E getLast(); 返回此列表的最后一個元素
public E removeFrist(); 移除並返回此列表的第一個元素
public E removeLast(); 移除並返回此列表的最后一個元素
public E pop(E e); 入此列表所示的堆棧中彈出一個元素。
public boolean isEmpty(); 如果列表為空 返回true
*/
import java.util.LinkedList;
import java.util.List;
public class TestLinkedList {
public static void main(String[] args) {
show01();
show02();
show03();
}
/*
public void addFirst(E e); 將指定的元素插到列表開頭。
public void addLast(E e); 將指定的元素插到列表結尾。
public void push(E e); 將元素推入此列表所示的堆棧
*/
public static void show01(){
// 注:LinkedList特有的方法不能使用多態!
// List<String> list = new LinkedList<>(); 是不對的
LinkedList<String>list = new LinkedList<>();
// add()添加元素
list.add("a");
list.add("b");
list.add("c");
System.out.println(list);//[a, b, c]
list.addFirst("hhh");
//public void push(E e); 將元素推入此列表所示的堆棧。 等效於addFirst()
list.push("hhh");
System.out.println(list);
//public void lastFrist(E e); 將指定的元素插到列表結尾。 等效於add()
list.addLast("com");
System.out.println(list);
}
/*
public E getFrist(); 返回此列表的第一個元素
public E getLast(); 返回此列表的最后一個元素
*/
public static void show02(){
LinkedList<String>list = new LinkedList<>();
// add()添加元素
list.add("a");
list.add("b");
list.add("c");
// list.clear(); // 清空集合中所有元素
if(! list.isEmpty()){
System.out.println(list.getFirst());//a
System.out.println(list.getLast());//c
}
}
/*
public E removeFrist(); 移除並返回此列表的第一個元素
public E removeLast(); 移除並返回此列表的最后一個元素
public E pop(E e); 入此列表所示的堆棧中彈出一個元素。
*/
public static void show03(){
LinkedList<String>list = new LinkedList<>();
// add()添加元素
list.add("a");
list.add("b");
list.add("c");