Java集合框架超詳細小結(jié)
一:Collection集合
呼~,歷過好幾天的奮戰(zhàn)終于把集合框架肝完了,b站某馬老師講的是真的非常詳細而且動聽,原理給你分析得明明白白的,此前也找了許多關(guān)于集合這一大章節(jié)的視頻,發(fā)現(xiàn)更多的是針對于使用,原理講的并不是很多,這就導(dǎo)致我在練習或者回顧時還是一知半解。以下是我結(jié)合視頻以及個人的一些理解和體會做的筆記總結(jié)。路漫漫其修遠兮,吾將上下而求索,希望這篇總結(jié)對你有些許幫助,嘻嘻!
1.1集合概述:
集合:Java中提供的一種容器,可以用來存儲多個數(shù)據(jù)。java集合大致可以分為Set,List,Queue和Map四種體系。
數(shù)組和集合的區(qū)別:
- 數(shù)組的長度是固定的。集合的長度是可變的。
- 數(shù)組存儲的是同一類型的數(shù)據(jù),可以存儲基本數(shù)據(jù)類型值。容器能存儲對象,而且存儲對象的類型可以不一致。在開發(fā)中當對象多的時候,使用容器進行存儲。
1.2集合架構(gòu)

單列集合體系結(jié)構(gòu):

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(); 將集合轉(zhuǎn)成一個數(shù)組
【參考代碼】
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(); 將集合轉(zhuǎn)成一個數(shù)組
*/
public class Test {
public static void main(String[] args) {
//創(chuàng)建集合對象 , 可以多態(tài)使用
Collection<String>col = new ArrayList<>();
// Collection<String>col = new HashSet<>(); 下面的功能照樣能實現(xiàn):共性方法
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(); 將集合轉(zhuǎn)成一個數(shù)組
Object[] arr = col.toArray();
// 遍歷數(shù)組
// for (int i = 0; i < arr.length; i++) {
// System.out.println(arr[i]);
// }
}
}
二:迭代器Iterator
引入:由于集合有多種,每種集合存儲跟讀取的方式都不一樣,好比衣柜、水瓶、藥瓶,你存和取的方式肯定不一樣。如果每種集合都定義一種遍歷方式那將十分的繁瑣。
迭代器(Iterator):它不是一個容器而是接口,它是一種用于訪問容器的方法,可用于迭代 List、Set和Map等容器。
迭代:即Collection集合的通用獲取方式。再獲取元素之前先要判斷集合中是否有元素,如果有就將這個元素去取出來,繼續(xù)再判斷,直到集合所有元素被取出來為止。即:一個一個的往外拿。
作用:幫我們遍歷或者拿到容器里邊的數(shù)據(jù)。
2.1Iterator接口
迭代器常用操作:
- next() 下一個
- hasNext() 判斷是否存在下一個元素
- remove() 刪除元素
迭代器的使用步驟:
- 使用集合中的的方法iterator()獲取迭代器的實現(xiàn)類對象,使用Iterator接口接收(多態(tài))
- 使用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) {
//創(chuàng)建一個集合對象
Collection<String>col = new ArrayList();
//添加元素
col.add("小明");
col.add("小紅");
col.add("小藍");
col.add("小綠");
/*
1.使用集合的方法iterator()獲取迭代器的實現(xiàn)類對象,使用Iterator接口接收(多態(tài))
注意:
Iterator接口也是有泛型的,迭代器的泛型跟集合走,集合是什么泛型,迭代器就是什么泛型
*/
// 多態(tài) 接口 實現(xiàn)類對象
Iterator<String>it = col.iterator();
// 2.使用 Iterator接口中的hashNext方法判斷是否還有下一個元素
while(it.hasNext());{
// 3.使用 Iterator接口中的next方法取出集合的下一個元素
String str = it.next();
System.out.println(str);
}
}
}
2.2Iterator的實現(xiàn)原理:

2.3增強for()
增強for循環(huán)(for each循環(huán))是JDk1.5之后的一個高循環(huán),專門用來遍歷數(shù)組和集合的,所有的數(shù)組跟單列集合都可以使用。它的內(nèi)部原理就是一個迭代器Iterator,所以在遍歷過程中,不能對集合元素進行增刪操作。
語法:
for(類型 變量 : 數(shù)組/集合){// 數(shù)組或者集合里的每一項賦值給這個變量
// 循環(huán)體
}
【參考代碼】
String[] student = {"小明","小紅","小藍"};
// // 傳統(tǒng)遍歷方式
// 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必須有被遍歷的目標。目標只能是數(shù)組或者Collection,而它僅僅作為遍歷操作實現(xiàn)
2.4迭代器注意事項
- 迭代器是一次性對象。我們不能重置迭代器,它不能被重用。
- 要再次遍歷同一集合的元素,請通過調(diào)用集合的iterator()方法來創(chuàng)建一個新的Iterator。
三:泛型
3.1泛型概述
在前面學習集合時,我們知道集合時可以存放任意對象的,只要把對象存儲集合后,它們都會被向上轉(zhuǎn)型提升為Object類型。當我們要取出這些對象時必須進行類型強制轉(zhuǎn)換,由Object類型變?yōu)樵瓉淼念愋汀?/p>

3.2泛型的優(yōu)缺點
不使用泛型:
- 好處:集合默認類型是Object類,可以存儲任意類型的數(shù)據(jù)
- 弊端:不安全,會引發(fā)異常,需要強轉(zhuǎn)。
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) // 強轉(zhuǎn)
System.out.println(s);
}
}
使用泛型:
- 好處:避免了類型強制轉(zhuǎn)化的麻煩,存的什么類型,取出來的也是什么類型;代碼運行之后才會拋出異常,寫代碼時不會報錯
- 弊端:泛型是什么類型只能存儲什么類型的數(shù)據(jù)。
public static void main(String[] args) {
List<String> list = new ArrayList();// 規(guī)范了數(shù)據(jù)類型,只能放字符串!
list.add("小明");
list.add("小紅");
//stringList.add(123);// 除了字符串以外的類型不能加,報錯!
for (int i = 0; i < list.size(); i++) {
String s = list.get(i); // 不用再強轉(zhuǎn)了
System.out.println(s);
}
}
在上述的實例中,我們只能添加String類型的數(shù)據(jù),否則編譯器會報錯。
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;
}
參考示例:

注:在創(chuàng)建對象時確定泛型的類型
泛型方法
定義格式:
修飾符 <泛型變量> 返回值的類型 方法名稱(形參列表){
//方法體
}
注:含有泛型的方法,在調(diào)用的時候確定泛型的數(shù)據(jù)類型
傳遞什么類型的參數(shù),泛型就是什么類型
參考示例:

泛型接口
定義格式:
public interface 接口名<泛型類型> {
}
使用方式1:定義接口的實現(xiàn)類,實現(xiàn)接口,并且指定接口的泛型

使用方式2:接口使用什么泛型,實現(xiàn)類就使用什么泛型,類跟著接口走。
就相當于定義了一個含有泛型的類,創(chuàng)建對象的時候確定泛型的類型。
下圖接口同上圖接口

3.4泛型的通配符
當使用泛型類或接口時,傳遞數(shù)據(jù)中,泛型類型不確定,可以通過通配符表示<?>表示。但一旦使用泛型的通配符后,只能使用Object類中的共性方法,集合中元素自身方法無法使用。
通配符的基本使用
泛型的通配符:不知道使用什么類型來接收的時候,此時可以使用 ? ,?表示未知通配符
此時只能接收數(shù)據(jù),不能往集合中存儲數(shù)據(jù)。
【參考代碼】
package FanXing;
import javax.swing.text.html.HTMLDocument;
import java.util.ArrayList;
import java.util.Iterator;
/*
泛型的通配符:
?:代表數(shù)據(jù)類型
使用方式:
不能在創(chuàng)建對象時使用
只能作為方法的傳遞參數(shù)使用
*/
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集合使用的是什么類型,可以使用泛型的通配符:?來代表數(shù)據(jù)類型
注意:泛型沒有繼承的概念
*/
}
public static void printArray(ArrayList<?>list){
// 使用迭代器遍歷集合
Iterator<?> it = list.iterator();
while(it.hasNext()){
Object obj = it.next();//it.next()取出的元素是Object類。Object類 可以接收任意的數(shù)據(jù)類型
System.out.println(obj);
}
}
}
通配符高級使用-----受限泛型
之前設(shè)置泛型的時候,實際上是可以可以任意設(shè)置的,只要是類就可以設(shè)置。但在Java的泛型中可以指定一個泛型的上限和下限。
泛型的上限:
- 格式:類型名稱<? extends E >對象名稱 代表的泛型只能是E類型的子類/本身
- 意義:只能接收該類型及其子集
泛型的下限:
- 格式:類型名稱<? super E >對象名稱 代表的泛型只能是E類型的父類/本身
- 意義:只能接收該類型及其父類
比如:Object類、String類、Number類、Integer類,其中Number類是Integer的父類。
四:Java常見數(shù)據(jù)結(jié)構(gòu)
集合是基于數(shù)據(jù)結(jié)構(gòu)做出來的,不同的集合底層采用不同的數(shù)據(jù)結(jié)構(gòu)。不同的數(shù)據(jù)結(jié)構(gòu),功能和作用是不一樣的。
數(shù)據(jù)結(jié)構(gòu)是指數(shù)據(jù)以什么方式組織在一起。不同的數(shù)據(jù)結(jié)構(gòu),增刪查的性能是不一樣的。
4.1棧
棧:stack,又稱堆棧,它是運算受限的線性表,只能在棧的受限一端進行插入和刪除操作。
特點:先進后出
4.2隊列
隊列:queue,簡稱隊,它同棧由于也是運算受限的線性表,只能在表的一端進行插入操作,而在表的另一端進行刪除操作。
特點:先進先出
4.3數(shù)組
數(shù)組:Array,是個有序的元素序列,數(shù)組在內(nèi)存中開辟一段連續(xù)的空間。
特點:
查詢快:隨機存取,通過索引可以快速訪問元素
增刪慢:靜態(tài)分配內(nèi)存,數(shù)組的長度是固定,存在空間閑置或者溢出現(xiàn)象;不適合進行插入和刪除操作,需要移動大量元素。
4.4鏈表
鏈表:linked list,由一系列結(jié)點node組成,結(jié)點可以在運行時動態(tài)產(chǎn)生。每個節(jié)點包含兩個部分:數(shù)據(jù)域(data)和指向下一個節(jié)點的指針域(next)。鏈表包括單鏈表和雙向鏈表。
單鏈表:鏈表中只有一條鏈子,不能保證元素的順序(存儲和取出的順序可能不一致)
雙向鏈表:鏈表中只有兩條鏈子,有一條鏈子專門記錄元素的順序,是一個有序的集合。
特點:
查詢慢:鏈表的地址不是連續(xù)的,每次查詢都要從頭到尾進行遍歷。
增刪快:動態(tài)分派內(nèi)存,增/刪一個節(jié)點對于鏈表整體結(jié)構(gòu)沒有影響,增刪操作效率高。
4.5紅黑樹
紅黑樹:R-B Tree,全稱是Red-Black Tree,又稱為“紅黑樹”,它一種特殊的二叉查找樹。紅黑樹的每個節(jié)點上都有存儲位表示節(jié)點的顏色,可以是紅(Red)或黑(Black),它是一種弱平衡二叉樹(Weak AVL)。
特點:
(1)每個節(jié)點或者是黑色,或者是紅色。 (2)根節(jié)點是黑色。 (3)每個葉子節(jié)點(NIL)是黑色。 [注意:這里葉子節(jié)點,是指為空(NIL或NULL)的葉子節(jié)點!] (4)如果一個節(jié)點是紅色的,則它的子節(jié)點必須是黑色的。 (5)從一個節(jié)點到該節(jié)點的子孫節(jié)點的所有路徑上包含相同數(shù)目的黑節(jié)點。
注:以上數(shù)據(jù)結(jié)構(gòu)可以結(jié)合所學過c語言數(shù)據(jù)結(jié)構(gòu)
五:List集合體系
5.1List概述
List集合體系:添加元素,是有序,可重復(fù),有索引的,大小可變。實際開發(fā)中常用的是ArrayList集合。List集合體系包括以下幾種:
- ArrayList——添加元素,是有序,可重復(fù),有索引的。
- LinkedList——添加元素,是有序,可重復(fù),有索引的。
- Vector——查詢快,增刪慢;運行效率慢、線程安全
List集合繼承了Collection集合的全部功能,同時因為List集合系列有索引,所以多了很多按照索引操作元素的方法:
add(int index, E element) 根據(jù)索引添加元素 get(int index) 根據(jù)索引獲取元素 remove(int index) 根據(jù)索引刪除元素 set(int index, E element) 根據(jù)索引修改該位置上的元素 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 下面的操作都能一樣實現(xiàn)
list.add("小明");
list.add("小紅");
list.add("小藍");
list.add("小綠");
list.add("小明");
// // 在某個索引位置往集合中添加元素
// list.add(2,"哈哈哈哈");
// System.out.println(list);
// // 刪除集合中某個元素
// list.remove("小藍");
// // 根據(jù)索引獲取元素
// 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循環(huán)
// 遍歷列表
for (int i = 0; i < list.size(); i++) {
String str = list.get(i);
System.out.println(str);
}
迭代器
Iterator<String>it = list.iterator(); // 創(chuàng)建一個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集合存儲的結(jié)構(gòu)是數(shù)組結(jié)構(gòu),元素增刪慢,查詢快。最常用。
5.4LinkedList集合
LinkedList集合存儲的結(jié)構(gòu)是鏈表結(jié)構(gòu),方便元素的添加、刪除操作。LinkedList是一個雙向鏈表
LinkedList的特點:
底層是一個鏈表結(jié)構(gòu):查詢慢,增刪快
里邊含有大量操作首尾元素的方法
注:使用LinkedList集合特有的方法,不能使用多態(tài),命名要注意了!
實際開發(fā)中對一個集合的添加、刪除操作經(jīng)常涉及首尾操作,LinkedList提供了很多操作首尾元素方法
public void addFirst(E e); 將指定的元素插到列表開頭。 public void addLat(E e); 將指定的元素插到列表結(jié)尾。 此方法等效于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); 將指定的元素插到列表結(jié)尾。
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); 將指定的元素插到列表結(jié)尾。
public void push(E e); 將元素推入此列表所示的堆棧
*/
public static void show01(){
// 注:LinkedList特有的方法不能使用多態(tài)!
// 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); 將指定的元素插到列表結(jié)尾。 等效于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");
System.out.println(list.pop());
//public E pop(E e); 入此列表所示的堆棧中彈出一個元素。 等效于 removefirst()
//System.out.println(list.pop());
System.out.println(list.removeFirst());//a
System.out.println(list.removeLast());//c
System.out.println(list);//[b]
}
}
注:使用LinkedList集合特有的方法,不能使用多態(tài)。
5.5Vector集合(了解)
數(shù)組結(jié)構(gòu)實現(xiàn),查詢快,增刪慢;
JDK1.0版本,運行效率慢、線程安全
【參考代碼】
package Collection;
import javax.swing.text.html.HTMLDocument;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Vector;
/*
Vector集合的使用
存儲結(jié)構(gòu):數(shù)組
*/
public class VectorTest {
public static void main(String[] args) {
// 創(chuàng)建集合
Vector<String>vector = new Vector<>();
// 添加元素
vector.add("小明");
vector.add("小紅");
vector.add("小藍");
System.out.println("元素個數(shù)"+ vector.size());
// 判斷
System.out.println(vector.contains("小明"));
System.out.println(vector.isEmpty());
//刪除
vector.remove("小紅");
System.out.println(vector);
//清空 clear(); vector.clear();
// 遍歷
Iterator<String> it = vector.iterator();
while (it.hasNext()){
String str = it.next();
System.out.println(str);
}
//vector獨有的遍歷 使用枚舉器
// Enumeration<String>en = vector.elements();
// while (en.hasMoreElements()){
// String s = en.nextElement();
// System.out.println(s);
// }
}
}
六:Set系列集合
6.1概述
Set系列集合:添加的元素,是無序的,不重復(fù)的,無索引的(索引的操作不能用)。
——HashSet:添加的元素,是無序的,不重復(fù)的,無索引的。
——LinkedHashSet:添加的元素,是有序的,不重復(fù)的,無索引的。
——TreeSet:不重復(fù),無索引,按照大小默認升序排序!!(可排序集合)
遍歷方式:由于Set集合五索引,故沒有for循環(huán)遍歷,只有三種遍歷。
6.2Set集合存儲元素不重復(fù)的原理

注:存儲的字符串,Integer等類型的數(shù)據(jù),它們是Java已經(jīng)定義好了類,它們都重寫了hashCode方法和equals方法,保證了元素的唯一性!
HashSet 保證元素唯一性的原理
我們使用 Set 集合都是需要去掉重復(fù)元素的, 如果在存儲的時候逐個 equals() 比較, 效率較低,哈希算法提高了去重復(fù)的效率, 降低了使用 equals() 方法的次數(shù)。
當 HashSet 調(diào)用 add() 方法存儲對象的時候, 先調(diào)用對象的 hashCode() 方法得到一個哈希值, 然后在集合中查找是否有哈希值相同的對象,如果沒有哈希值相同的對象就直接存入集合。如果有哈希值相同的對象, 就和哈希值相同的對象逐個進行 equals() 比較,比較結(jié)果為 false 就存入, true 則不存。存儲元素必需要重寫HashCode方法和equals方法
6.3HashSet存儲自定義類型元素
給HashSet中存放自定義的類型時,必需要重寫HashCode方法和equals方法,建立自己的比較方式,才能保證HashSet集合中對象的唯一性!
【參考代碼】
Person類:
package Collection;
import java.util.Objects;
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 用于打印
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
// 重寫hashCode方法和equals方法
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
// 主控制臺
package Collection;
import java.util.HashSet;
import java.util.Set;
/*
HashSet存儲自定義類型的元素
Set集合保證元素唯一性:
存儲的元素(String Integer,...Student,Person...) 必須重寫hashCode方法和equals方法
要求:
同名且同年齡視為同一個人噢
*/
public class TestHaxhSet {
public static void main(String[] args) {
// 創(chuàng)建hashSet集合存儲Person
Set<Person>set = new HashSet<>();
//集合類存放對象的!
// 創(chuàng)建對象(人)
/*
// 在沒有重寫hashCode方法和equals方法前,它們的哈希值都是不一樣的,equals也為false 故沒有重復(fù)
Person p1 = new Person("小明",18);
Person p2 = new Person("小明",19);
Person p3 = new Person("小明",18);
System.out.println(p1.hashCode());// 460141958
System.out.println(p2.hashCode());// 1163157884
System.out.println(p3.hashCode());// 1956725890
System.out.println(p1.equals(p2));// false
set.add(p1);
set.add(p2);
set.add(p3);
System.out.println(set);// [Person{name='小明', age=18}, Person{name='小明', age=19}, Person{name='小明', age=18}]
*/
// 重寫hashCode方法和equals方法之后set對象就唯一性了
Person p1 = new Person("小明",18);
Person p2 = new Person("小明",19);
Person p3 = new Person("小明",18);
set.add(p1);
set.add(p2);
set.add(p3);
System.out.println(set);// [Person{name='小明', age=19}, Person{name='小明', age=18}]
}
}
6.4LinkedHashSet集合
我們知道HashSet保證元素的唯一性,但存放進去的元素是無序的,那我們要保證有序,該怎么辦好呢?
在HashSet下面的一個子類Java.util.LinkedHashSet。它是鏈表和哈希表組合的一個數(shù)據(jù)結(jié)構(gòu)。
LinkedHashSet集合的特點:
底層是一個哈希表(數(shù)組+鏈表/紅黑樹)+鏈表:多了一條鏈表(記錄元素的存儲順序),保證元素有序
具有可預(yù)知迭代順序的 Set 接口的哈希表和鏈接列表實現(xiàn),即按照將元素插入到 set 中的順序(插入順序)進行迭代。
HashSet與LinkedHashSet的區(qū)別:
【參考代碼】
package Collection;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
public class TestHashSet {
public static void main(String[] args) {
Set<String>set = new HashSet<>();
set.add("kkk");
set.add("abc");
set.add("abc");
set.add("afterglow");
System.out.println(set);//[afterglow, abc, kkk] 無序,不重復(fù)
Set<String>Linkset = new LinkedHashSet<>();
Linkset.add("kkk");
Linkset.add("abc");
Linkset.add("abc");
Linkset.add("afterglow");
System.out.println(Linkset);//[kkk, abc, afterglow] 有序,不重復(fù)
}
}
6.5可變參數(shù)
使用前提:
如果我們定義一個方法需要接收多個參數(shù),并且多個參數(shù)類型一致,我們可以對其做如下格式的簡化:
修飾符 返回值類型 方法名(參數(shù)類型... 形參名){ }
這個寫法完全等價于:
修飾符 返回值類型 方法名(參數(shù)類型[] 形參名){ } ,
后者在調(diào)用時必須傳遞數(shù)組,而前者可以直接傳遞數(shù)據(jù)類型。
可變參數(shù)原理:
可變參數(shù)底層是一個數(shù)組,根據(jù)參數(shù)個數(shù)不同,會創(chuàng)建不同長度的數(shù)組來存儲這些參數(shù)。傳遞參數(shù)的個數(shù),可以是0~n個
【參考代碼】
package Collection;
public class KeBiancanShu {
public static void main(String[] args) {
int i =add(1,2,3,4);
System.out.println(i);
}
// // 兩個數(shù)的和
// public static int add(int a, int b){
// return a + b;
// }
// // 三個數(shù)的和,要是多個一直往下寫,很麻煩!
// public static int add(int a, int b, int c){
// return a + b +c;
// }
/*
求0~n個整數(shù)的和
數(shù)據(jù)類型已經(jīng)確定:int
參數(shù)個數(shù)不確定,可以使用可變參數(shù)
*/
public static int add(int...arr){
// System.out.println(arr);// [I@1b6d3586 底層是一個數(shù)組
// System.out.println(arr.length);// 可變數(shù)組的長度,卻決于你添加的個數(shù)
int sum = 0;
for (int i : arr){
sum += i;
}
return sum;
}
}
注意事項:
- 一個方法的參數(shù)列表,只能有一個可變參數(shù)
- 如果方法的參數(shù)有多個,那么可變參數(shù)必須寫在參數(shù)列表的末尾!
【示例代碼】
/*
可變參數(shù)注意事項:
一個方法的參數(shù)列表,只能有一個可變參數(shù)
如果方法的參數(shù)有多個,那么可變參數(shù)必須寫在參數(shù)列表的末尾!
*/
//一個方法的參數(shù)列表,只能有一個可變參數(shù)
// public static void method01(int...a,String...b){ 報錯!
// }
//如果方法的參數(shù)有多個,那么可變參數(shù)必須寫在參數(shù)列表的末尾!
public static void method02(String b, double c, int...a){
}
七:Collections工具類
7.1常用方法:
- Java.utils.collections 是集合工具類,用于對集合進行操作。常用功能如下:
max() / min():求集合的最大 / 小值public static <T> boolenan addAll(Collect<T> c , T. . . elements):往集合中添加一些元素public static void shuffle(List<?> list):打亂集合順序public static void sort(List<T> list):將集合按照默認規(guī)則(升序)進行排序public static void sort(List<T> list , Comparator<? super T >);將集合按照指定的規(guī)則進行排序
【參考代碼】
public class Test {
public static void main(String[] args) {
List<Integer>list = new ArrayList<Integer>();
list.add(120);
list.add(20);
list.add(220);
// 求最值
Integer max = Collections.max(list);
System.out.println(max);
Integer min = Collections.min(list);
System.out.println(min);
// 排序
Collections.sort(list);
System.out.println(list);
// 打亂順序
Collections.shuffle(list); // 斗地主發(fā)牌
System.out.println(list);
// 不定參數(shù)添加
Collections.addAll(list,456,789);
System.out.println(list);//[220, 20, 120, 456, 789]
}
}
sort(List < T > list)使用
注意:
sort(List<T> list)使用前提:
排序的集合里邊存儲的元素,必須實現(xiàn)Comparable接口,重寫接口中的方法compareTo定義排序的規(guī)則。在Java中Integer、String等等數(shù)據(jù)類型已經(jīng)幫我們實現(xiàn)Comparable接口并重寫接口中的方法compareTo了。如果要對自己定義的類進行排序,我們就要自己實現(xiàn)接口并重寫compareTo然后進行自定義排序規(guī)則。
Comparable接口的排序規(guī)則:
自己(this) - 參數(shù):升序,反之降序
【示例參考】:比較自定義類型

輸出結(jié)果:
[Student{name='小明', age=18}, Student{name='小紅', age=20}, Student{name='小藍', age=19}] [Student{name='小明', age=18}, Student{name='小藍', age=19}, Student{name='小紅', age=20}]
- sort(List< T > list , Comparator<? super T >)
- sort(List< T > list , Comparator<? super T >)的使用:
- Comparator:相當于找一個第三放的裁判,按照Comparator比較器里面重寫的compare方法對元素進行排序比較
Comparator的比較規(guī)則:
o1 - o2 升序
【參考代碼】
public class TestComparator {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(2);
list.add(1);
list.add(3);
Collections.sort(list, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;// 升序
// return o2 - o1;// 降序
}
});
System.out.println(list);// [1, 2, 3]
}
}
【示例參考】:比較自定義類型

Comparator和Comparable的區(qū)別
- Comparable:自己(this)和別人(參數(shù))比較,自己需要實現(xiàn)Comparable接口,重寫比較規(guī)則compareTo方法
- Comparator:相當于找一個第三放的裁判,按照Comparator比較器里面重寫的compare方法對元素進行排序比較
八:Map集合
8.1概述
Map集合的特點
- Map是一個雙列集合,其中每個元素表示一個鍵值對作為<key,value> ;
- Map集合中的元素,key和value的數(shù)據(jù)類型可以相同,也可以不同
- Map集合中的元素,key不允許出現(xiàn)重復(fù),value可以重復(fù)
- Map集合中的元素,key和value是一一對應(yīng)的(映射)
注:映射由Map<K,V>接口的實例表示,它不是繼承自Collection接口。
8.2Map集合常見子類
Map系列集合,常用子類的包括:
——HashMap
——LinkedHashMap
【HashMap集合】
java.util.HashMap<k , v >集合implements Map<k , v>接口.
HashMap集合的特點:
HashMap底層是哈希表:查詢速度特別快
JDK1.8之前:數(shù)組 + 單項鏈表
JDK1.8之后:數(shù)組 + 單項鏈表/紅黑樹(鏈表長度超過8):提高查詢速
HashMap集合是一個無序的集合,存儲元素和取出元素的順序有可能不一致
【LinkedHashMap集合】
java.util.LinkedHashMap<k , v >集合extends HashMap<k , v>集合。
LinkedHashMap集合的特點:
LinkedHashMap底層是哈希表 + 鏈表(保證迭代的順序)
HashMap集合是一個有序的集合,存儲元素和取出元素的順序是一致的
8.3Map接口中的常用方法
Map接口中定義了很多方法,常見如下:
public V put(K key , V value):把指定的鍵(key)和指定的值(value)添加到Map集合中public V remove(Object key):把指定的key所對應(yīng)的value從Map集合中刪除,返回被刪元素的值public V get(Object key):在集合中獲取指定key對應(yīng)value的元素boolean containsKey(Object key):判斷集合中是否含有xxxkeyboolean containsValue(Object key):判斷集合中是否含有xxxvaluepublic Set<K> KeySet():把Map中所有的key打包成(存儲到)set集合返回public Set< Map.Entry<K,V> > entrySet():獲取Map中所有key和value對象的集合(Entry)存儲在集合Set中
【參考代碼】
package Map;
import java.util.HashMap;
import java.util.Map;
public class Test {
public static void main(String[] args) {
// 創(chuàng)建Map集合對象,多態(tài)
Map<Integer,String>map = new HashMap();
map.put(11,"小明");
map.put(22,"小紅");
map.put(33,"小藍");
map.put(44,"小綠");
System.out.println(map);// {33=小藍, 22=小紅, 11=小明, 44=小綠} HashMap無序的
map.remove(44);// 刪除
System.out.println(map);// {33=小藍, 22=小紅, 11=小明}
System.out.println(map.size()); //大小 3
System.out.println(map.containsKey(33)); //true
System.out.println(map.containsValue("小藍")); //true
map.put(22,"小芳"); // {33=小藍, 22=小芳, 11=小明} 若出現(xiàn)重復(fù)的key原來的數(shù)據(jù)會被頂替
System.out.println(map);
// map.put(55,"小明");
// System.out.println(map);//是否被頂替卻決于key,key映射value,而不是value映射key {33=小藍, 22=小芳, 55=小明, 11=小明}
System.out.println(map.keySet()); // [33, 22, 11] 把map中的key打包成Set集合的形式
System.out.println(map.get(33));// 小藍 通過key查詢value
}
}
8.4Map的遍歷
方法一:通過鍵找值的方式
- 使用Map集合中的方法keySet(),把Map集合里所有的key取出來,存放到一個Set集合中
- 遍歷set集合,獲取Map集合中的每一個key
- 通過Map集合中的get(key)方法,找到value
【參考代碼】
package Map;
import javax.swing.text.html.HTMLDocument;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class Test {
public static void main(String[] args) {
// 創(chuàng)建Map集合對象
Map<String,Integer>map = new HashMap<>();
map.put("小明",18);
map.put("小紅",18);
map.put("小藍",19);
map.put("小綠",20);
//1. 使用Map集合中的方法keySet(),把Map集合里所有的key取出來,存放到一個Set集合中\(zhòng)
Set<String> set = map.keySet();
//2.遍歷set集合,獲取Map集合中的每一個key
/* 使用while遍歷 */
Iterator <String> it = set.iterator();
while (it.hasNext()){
String key = it.next();
//3.通過Map集合中的get(key)方法,找到value
Integer value = map.get(key);
System.out.println(key+"="+value);
}
System.out.println("-----------------------");
/* 使用增強for遍歷 */
for(String key : set){
//3.通過Map集合中的get(key)方法,找到value
Integer value = map.get(key);
System.out.println(key+"="+value);
}
}
}
【總結(jié)】:
while——迭代器遍歷:
Set<String> set = map.keySet();
Iterator <String> it = set.iterator();
while (it.hasNext()){
String key = it.next();
Integer value = map.get(key);
System.out.println(key+"="+value);
}
增強for遍歷:
Set<String> set = map.keySet();
for(String key : set){
//3.通過Map集合中的get(key)方法,找到value
Integer value = map.get(key);
System.out.println(key+"="+value);
}
方法二:鍵值對的方式遍歷(更加面向?qū)ο螅?/p>
把鍵值對當成一個整體遍歷,增強for無法遍歷,這個整體不是類型,因此Java提供了方法:
Map集合通過代碼Set<Map.Entry<K,V>> ,將鍵值對元素轉(zhuǎn)成了一個實體類型,此時得到的是一個Entry對象,類型是:Map.Entry<K,V>
- 通過Map集合中的entrySet()方法,把Map集合中的多個Entry對象取出來,存儲到一個Set集合中
- 此時鍵值對元素的類型就確定了,類型是鍵值對實體類型:Map.Entry<K,V>
- 接下來就可以用增強for遍歷了
【參考代碼】
package Map;
import javax.swing.text.html.HTMLDocument;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class Test {
public static void main(String[] args) {
// 創(chuàng)建Map集合對象
Map<String,Integer>map = new HashMap<>();
map.put("小明",18);
map.put("小紅",18);
map.put("小藍",19);
map.put("小綠",20);
//1.通過Map集合中的entrySet()方法,把Map集合中的多個Entry對象取出來,存儲到一個Set集合中
Set<Map.Entry<String,Integer>> set = map.entrySet();
//遍歷set集合,獲取每一個Entry對象
//使用迭代器遍歷set集合
Iterator <Map.Entry<String,Integer>> it = set.iterator();
while (it.hasNext()){
Map.Entry<String,Integer>entry = it.next();
// 使用Entry對象中的getKey()和getValue()方法獲取鍵和值
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key+"="+value);
}
System.out.println("-----------");
//增強for
for(Map.Entry<String,Integer> entry : set){
// 使用Entry對象中的getKey()和getValue()方法獲取鍵和值
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key+"="+value);
}
}
}
【總結(jié)】:
while——迭代器遍歷:
Set<Map.Entry<String,Integer>> set = map.entrySet();
//遍歷set集合,獲取每一個Entry對象
//使用迭代器遍歷set集合
Iterator <Map.Entry<String,Integer>> it = set.iterator();
while (it.hasNext()){
Map.Entry<String,Integer>entry = it.next();
// 使用Entry對象中的getKey()和getValue()方法獲取鍵和值
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key+"="+value);
}
增強for遍歷:
//增強for
for(Map.Entry<String,Integer> entry : set){
// 使用Entry對象中的getKey()和getValue()方法獲取鍵和值
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key+"="+value);
}
Entry:表示一個key和value,它提供了獲取對應(yīng)key和value的方法:
public K getKey():獲取Entry中的key
public V getValue():獲取Entry中的value
方法二圖解:

8.5HashMap存儲自定義類型鍵值
練習:每位學生(姓名,年齡)都有自己的家庭住址。那么,既然有對應(yīng)關(guān)系,則將學生對象和家庭住址存儲到map集合中,學生作為鍵,地址為值。
注:學生姓名、年齡相同則視為同一人
package Map;
/*
hashMap存儲自定義類型鍵值:
Map集合保證key是唯一的:
作為key元素,必須重寫hashMap方法和equals方法,以保證key唯一
*/
import java.util.HashMap;
import java.util.Set;
public class HashMapSavePerson {
public static void main(String[] args) {
show01();
/*
上海-->HashMapSavePerson{name='小藍', age=18}
深圳-->HashMapSavePerson{name='小綠', age=18}
北京-->HashMapSavePerson{name='小紅', age=18}
key唯一
*/
}
/*
hashMap存儲自定義類型鍵值:
key:String類型
String類重寫hashCode方法和equals方法,可以保證key唯一
value:Person類型
value可以重復(fù)(同名同年齡視為重復(fù))
*/
public static void show01(){
// 創(chuàng)造HashMap集合
HashMap<String,Person> map = new HashMap<>();
//往集合中添加元素
map.put("深圳",new Person("小明",18));
map.put("上海",new Person("小藍",18));
map.put("北京",new Person("小紅",18));
map.put("深圳",new Person("小綠",18));
// 使用keySet()增強for遍歷map集合
Set<String> set = map.keySet();
for(String key:set){
Person value = map.get(key);
System.out.println(key+"-->"+value);
// 因為字符串類(Java幫我們的)重寫了hashCode方法和equals方法,所以鍵(key)是不能重復(fù)的
}
}
}
Person類:

下面這個是我們自己定義的key的類型,Person類,上面例子的是String類:
package Map;
/*
hashMap存儲自定義類型鍵值:
Map集合保證key是唯一的:
作為key元素,必須重寫hashMap方法和equals方法,以保證key唯一
*/
import javax.swing.text.html.HTMLDocument;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class HashMapSavePerson {
public static void main(String[] args) {
show02();
}
/*
hashMap存儲自定義類型鍵值:
key:Person類型
Person就必須類重寫hashCode方法和equals方法,來保證key唯一
value:String類型
value可以重復(fù)(同名同年齡視為重復(fù))
*/
public static void show02(){
// 創(chuàng)造HashMap集合
HashMap<Person,String> map02 = new HashMap<>();
// 往集合中添加元素
map02.put(new Person("張三",18),"法外狂徒");
map02.put(new Person("黃老板",18),"英國");
map02.put(new Person("陳奕迅",18),"中國");
map02.put(new Person("張三",18),"法外狂徒");
// 使用迭代器遍歷set集合中的Entry對象
Set<Map.Entry<Person,String>> set = map02.entrySet();
Iterator<Map.Entry<Person,String>> it = set.iterator();
while(it.hasNext()){
Map.Entry<Person,String> entry = it.next();
Person key = entry.getKey();
String value = entry.getValue();
System.out.println(key+"--->"+value);
}
}
}

這里再介紹一下本例中Entry對象遍歷的圖解,再次加深印象:

8.6LinkedHashMap集合
我們知道HashMap保證key唯一,并且查詢速度快,可是成對元素存放進去是沒有順序的(存和取的順序可能不一致),那我們要如何保證順序呢?
在HashMap下面有個LinkedHashMap(繼承關(guān)系),它是鏈表(記錄元素的順序)和哈希表組合的一個數(shù)據(jù)存儲結(jié)構(gòu),是個有序的集合
【參考代碼】
package Map;
import javax.swing.text.html.HTMLDocument;
import java.util.*;
public class Test {
public static void main(String[] args) {
HashMap<String,String> map = new LinkedHashMap<>();
map.put("a","a");
map.put("c","c");
map.put("b","b");
map.put("d","d");
System.out.println(map);//{a=a, c=c, b=b, d=d}
}
}
輸出結(jié)果:(存儲和取出的順序是一樣的)
{a=a, c=c, b=b, d=d}
總結(jié)
看到這里,相信各位小伙伴們對Java集合這一章節(jié)的知識有了進一步的理解,尤其是一些在之前學習時可能沒有注意到的知識或者原理,沒關(guān)系,這次都幫你總結(jié)在一起了。最后,感謝看到這里的你!愿你韶華不負,青春無悔!
注: 由于自己剛剛開始學習Java不久,語言文字描述、技術(shù)等各方面還不是很好,如果文章有任何錯誤和建議,請各位大佬盡情評論留言!如果這篇文章對你有些許幫助,希望可愛親切的您點個贊推薦一手,非常感謝啦

到此這篇關(guān)于Java集合框架超詳細小結(jié)的文章就介紹到這了,更多相關(guān)Java集合框架內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java四種引用及在LeakCanery中應(yīng)用詳解
這篇文章主要介紹了java四種引用及在LeakCanery中應(yīng)用,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-09-09
SVN出現(xiàn)提示org.apache.subversion.javahl.ClientException: Attempt
這篇文章主要介紹了SVN出現(xiàn)提示org.apache.subversion.javahl.ClientException: Attempted to lock an already-locked dir解決方案的相關(guān)資料,需要的朋友可以參考下2016-12-12
java使用selenium自動化WebDriver等待的示例代碼
顯式等待和隱式等待是WebDriver中兩種常用的等待方式,它們都可以用來等待特定的條件滿足后再繼續(xù)執(zhí)行代碼,本文給大家介紹java使用selenium自動化WebDriver等待,感興趣的朋友一起看看吧2023-09-09
Java BigDecimal解決double精度丟失的問題
我們在日常開發(fā)中, 有很多時候會遇到小數(shù)(double類型)精確計算,本文主要介紹了Java BigDecimal解決double精度丟失的問題,具有一定的參考價值,感興趣的可以了解一下2023-11-11

