最全的集合筆記(乾貨)
1.集合基礎
1.1集合概述
集合類的特點:提供一種儲存空間可變的儲存模型,泛型。
ArrayList:
- 可調整大小的陣列實現
是一種特殊的資料型別,泛型。
怎麼用:
- 在出現E的地方使用引用資料型別替換即可
- 例:ArrayList
,ArrayList
1.2ArrayList構造方法和新增方法
- public ArrayList() 建立一個空的集合物件
- public boolean add(E e) 將指定的元素追加到此集合的末尾
- public void add(int index,E element) 在此集合的指定位置插入指定元素
- Demo01.java
package com.guoba.day1215.arraylist; import java.util.ArrayList; public class Demo01 { public static void main(String[] args) { ArrayList<String> arrayList = new ArrayList<String>(); //新增元素 arrayList.add("hello");//0 arrayList.add("arraylist");//1 arrayList.add("good happy");//2 //arrayList.remove("hello"); //arrayList.set(2,"javase"); System.out.println(arrayList.get(0)); System.out.println(arrayList.get(1)); System.out.println(arrayList.get(2)); //System.out.println(arrayList.get(3));//IndexOutOfBoundsException //System.out.println(arrayList.size()); System.out.println(arrayList); } }
1.3ArrayList集合常用方法
- public boolean remove(Obiject o) 刪除指定元素,返回刪除是否成功
- public E remove(int index) 刪除指定索引初的元素,返回被刪除的元素
- public E set(int index,E element) 修改......
- public E get(int index) 返回指定索引處的元素
- public int size() 返回集合元素的個數(類似length)
- Demo_BianLiStudent.java
package com.guoba.studentinformationmanagement;
/*
學生類
*/
public class Student {
private int id;
private String name;
private String sex;
private int fraction;//分數
public Student() {
}
public Student(int id, String name, String sex, int fraction) {
this.id = id;
this.name = name;
this.sex = sex;
this.fraction = fraction;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getFraction() {
return fraction;
}
public void setFraction(int fraction) {
this.fraction = fraction;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", sex='" + sex + '\'' +
", fraction=" + fraction +
'}';
}
}
package com.guoba.day1215.arraylist;
import com.guoba.studentinformationmanagement.Student;
import java.util.ArrayList;
public class Demo_BianLiStudent {
public static void main(String[] args) {
//建立集合物件
ArrayList<Student> as = new ArrayList<>(3);
//建立學生物件,並新增學生資訊
Student student1 = new Student(1,"劉備","男",90);
Student student2 = new Student(2,"張飛","男",89);
Student student3 = new Student(3,"關羽","男",96);
//為集合新增學生物件
as.add(student1);
as.add(student2);
as.add(student3);
//迴圈遍歷集合物件
for (int i = 0; i < as.size(); i++) {
System.out.println(as.get(i).getId()+as.get(i).getName()+as.get(i).getSex()+as.get(i).getFraction());
}
}
}
1.4Arraylist特點
- (1)底層使用陣列,有序可重複
- (2)查詢快,增刪慢
- (3)執行緒不安全,執行速度快
1.5使用場景:
- 當需要對資料進行遍歷訪問的情況下選用Array List
2.集合進階
2.1Collection(單列)
Collection集合概述和使用
- 集合概述
- 是單列集合的頂層介面,它表示一組物件,這些物件也稱為Cellction的元素
- JDK不提供此介面的任何實現,它提供更具體的子介面(如Set和List)實現
- 建立Cellection集合的物件
- 多型的方式
- 具體的實現類ArrayList
- 練習
(1)回顧
- 特點
- 提供一種儲存空間可變的儲存模型,儲存的資料容量可以隨時發生改變
(2)體系結構
List
- 元素是有序的、可重複,可以對列表中每個元素的插入位置進行精確地控制。
- 是一個有序容器,保持了每個元素的插入順序,輸出的順序就是插入的順序。
- 常用的實現類有 ArrayList、LinkedList 和 Vector。
2.2List
List介面的實現類
ArrayList
用法:
1.新增元素:add()
2.刪除元素:remove()
3.清空元素:clear()
4.集合長度:size()
步驟:
1.List
2.新增元素
3.for迴圈遍歷
for(int i = 0;i<list.size();i++){
System.out.println(list.get(i));
}
特點:
(1)底層使用陣列,有序、可重複
(2)查詢快,增刪慢
(3)執行緒不安全,執行速度快
使用場景
當需要對資料進行遍歷訪問的情況下用ArrayList
- ArrayList底層使用了Object的陣列作為容器去儲存資料
- ArrayList 提供了使用索引的隨意訪問資料
- ArrayList 是執行緒非安全的,效率較高,查詢速度高
LinkedList
特點:
- LinkedList底層使用了連結串列的資料結構
- LinkedList隨機位置插入、刪除資料時比線性錶快,遍歷比線性錶慢。
- 相對於ArrayList,LinkedList 對於經常需要從 List 中新增或刪除元素的場合更為合適。
- 和LinkedList一樣,ArrayList也是非同步的(unsynchronized)
- 查詢慢,增刪快
- 執行緒不安全,執行速度快
用法:
- 起始位置新增元素:addFirst();
- 末尾位置新增元素:addLast();
- 刪除起始位置元素:removeFirst();
- 刪除末尾位置元素:removeLast();
步驟:
1.建立LinkedList集合
2.新增元素add()
3.foreach遍歷/迭代器
使用場景:
對資料進行多次增刪和修改時採用LinkedList。
LinkedList和ArrayList集合的區別
- ArrayList:底層原理陣列,有序可重複,有索引,長度可變,增刪慢,查詢快。
- LinkedList:底層是連結串列,無下標,增刪快,查詢慢
Vector
- Vector非常類似ArrayList,但是Vector是同步的,效率相對比較低
- Vector的底層結構也是陣列,但是它們對陣列的擴容方式不同
- 查詢快,增刪慢,效率低,執行緒安全
- 當Vector或ArrayList中的元素超過它的初始大小時,Vector會將它的容量翻倍,而ArrayList只增加50%的大小,這樣ArrayList就有利於節約記憶體空間。
即Vector增長原來的一倍,ArrayList增加原來的0.5倍。
Stack棧繼承於Vector,棧的儲存特點是後進先出,
它基於動態陣列實現的一個執行緒安全的棧,所以棧是執行緒安全的。
Set
- 元素無序的、不可重複。
- 無序容器,你無法保證每個元素的儲存順序,但是其中的TreeSet是特別的,TreeSet通過 Comparator 或者 Comparable 維護了一個排序順序。
- 取出元素的方法只有迭代器和增強型for。
- 只允許一個 null 元素
- Set 介面最流行的幾個實現類是 HashSet、LinkedHashSet 以及 TreeSet。
- Set和Map的底層聯絡密切,可以說想要了解Set直接先了解好Map即可
- Set說白了就是對Map的功能的限制
HashSet
用法:
- 是否有下一個:hasNext();
- 有下一個:next();
- 刪除:remove();
- hashcode();判斷雜湊碼值相等
- equals(); 判斷兩個物件
特點:
(1)底層使用hashtable,無序不可重複
(2)無下標,沒有get方法,遍歷只能iterator
(3)執行緒不安全,執行速度快
使用場景
快速查詢。
概述:
-
HashSet底層實現其實是HashMap(看原始碼可以知道)
-
HashSet實現了Set介面,它不允許集合中出現重複元素。
-
將物件儲存在HashSet之前,要確保重寫hashCode()方法和equals()方法,這樣才能比較物件的值是否相等,確保集合中沒有儲存相同的物件。
-
HashSet實現Set介面,由雜湊表(實際上是一個HashMap例項)支援。
-
在HashSet中,元素都存到HashMap鍵值對的Key上面,而Value時有一個統一的值private static final Object PRESENT = new Object();
-
當有新值加入時,底層的HashMap會判斷Key值是否存在
-
執行緒非安全的
-
hashSet原始碼:
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
{
static final long serialVersionUID = -5024744406713321676L;
// 底層使用HashMap來儲存HashSet中所有元素。
private transient HashMap<E,Object> map;
// 定義一個虛擬的Object物件作為HashMap的value,將此物件定義為static final。
private static final Object PRESENT = new Object();
/**
* 預設的無參構造器,構造一個空的HashSet。
*
* 實際底層會初始化一個空的HashMap,並使用預設初始容量為16和載入因子0.75。
*/
public HashSet() {
map = new HashMap<E,Object>();
}
/**
* 構造一個包含指定collection中的元素的新set。
*
* 實際底層使用預設的載入因子0.75和足以包含指定
* collection中所有元素的初始容量來建立一個HashMap。
* @param c 其中的元素將存放在此set中的collection。
*/
public HashSet(Collection<? extends E> c) {
map = new HashMap<E,Object>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
/**
* 以指定的initialCapacity和loadFactor構造一個空的HashSet。
*
* 實際底層以相應的引數構造一個空的HashMap。
* @param initialCapacity 初始容量。
* @param loadFactor 載入因子。
*/
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<E,Object>(initialCapacity, loadFactor);
}
/**
* 以指定的initialCapacity構造一個空的HashSet。
*
* 實際底層以相應的引數及載入因子loadFactor為0.75構造一個空的HashMap。
* @param initialCapacity 初始容量。
*/
public HashSet(int initialCapacity) {
map = new HashMap<E,Object>(initialCapacity);
}
/**
* 以指定的initialCapacity和loadFactor構造一個新的空連結雜湊集合。
* 此建構函式為包訪問許可權,不對外公開,實際只是是對LinkedHashSet的支援。
*
* 實際底層會以指定的引數構造一個空LinkedHashMap例項來實現。
* @param initialCapacity 初始容量。
* @param loadFactor 載入因子。
* @param dummy 標記。
*/
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);
}
/**
* 返回對此set中元素進行迭代的迭代器。返回元素的順序並不是特定的。
*
* 底層實際呼叫底層HashMap的keySet來返回所有的key。
* 可見HashSet中的元素,只是存放在了底層HashMap的key上,
* value使用一個static final的Object物件標識。
* @return 對此set中元素進行迭代的Iterator。
*/
public Iterator<E> iterator() {
return map.keySet().iterator();
}
/**
* 返回此set中的元素的數量(set的容量)。
*
* 底層實際呼叫HashMap的size()方法返回Entry的數量,就得到該Set中元素的個數。
* @return 此set中的元素的數量(set的容量)。
*/
public int size() {
return map.size();
}
/**
* 如果此set不包含任何元素,則返回true。
*
* 底層實際呼叫HashMap的isEmpty()判斷該HashSet是否為空。
* @return 如果此set不包含任何元素,則返回true。
*/
public boolean isEmpty() {
return map.isEmpty();
}
/**
* 如果此set包含指定元素,則返回true。
* 更確切地講,當且僅當此set包含一個滿足(o==null ? e==null : o.equals(e))
* 的e元素時,返回true。
*
* 底層實際呼叫HashMap的containsKey判斷是否包含指定key。
* @param o 在此set中的存在已得到測試的元素。
* @return 如果此set包含指定元素,則返回true。
*/
public boolean contains(Object o) {
return map.containsKey(o);
}
/**
* 如果此set中尚未包含指定元素,則新增指定元素。
* 更確切地講,如果此 set 沒有包含滿足(e==null ? e2==null : e.equals(e2))
* 的元素e2,則向此set 新增指定的元素e。
* 如果此set已包含該元素,則該呼叫不更改set並返回false。
*
* 底層實際將將該元素作為key放入HashMap。
* 由於HashMap的put()方法新增key-value對時,當新放入HashMap的Entry中key
* 與集合中原有Entry的key相同(hashCode()返回值相等,通過equals比較也返回true),
* 新新增的Entry的value會將覆蓋原來Entry的value,但key不會有任何改變,
* 因此如果向HashSet中新增一個已經存在的元素時,新新增的集合元素將不會被放入HashMap中,
* 原來的元素也不會有任何改變,這也就滿足了Set中元素不重複的特性。
* @param e 將新增到此set中的元素。
* @return 如果此set尚未包含指定元素,則返回true。
*/
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
/**
* 如果指定元素存在於此set中,則將其移除。
* 更確切地講,如果此set包含一個滿足(o==null ? e==null : o.equals(e))的元素e,
* 則將其移除。如果此set已包含該元素,則返回true
* (或者:如果此set因呼叫而發生更改,則返回true)。(一旦呼叫返回,則此set不再包含該元素)。
*
* 底層實際呼叫HashMap的remove方法刪除指定Entry。
* @param o 如果存在於此set中則需要將其移除的物件。
* @return 如果set包含指定元素,則返回true。
*/
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
/**
* 從此set中移除所有元素。此呼叫返回後,該set將為空。
*
* 底層實際呼叫HashMap的clear方法清空Entry中所有元素。
*/
public void clear() {
map.clear();
}
/**
* 返回此HashSet例項的淺表副本:並沒有複製這些元素本身。
*
* 底層實際呼叫HashMap的clone()方法,獲取HashMap的淺表副本,並設定到HashSet中。
*/
public Object clone() {
try {
HashSet<E> newSet = (HashSet<E>) super.clone();
newSet.map = (HashMap<E, Object>) map.clone();
return newSet;
} catch (CloneNotSupportedException e) {
throw new InternalError();
}
}
}
TreeSet(二叉樹):
特點:
元素有序,這裡的順序不是值儲存和取出的順序,而是按照一定的規則進行排序,具體排序的方式取決於構造方法。
- TreeSet():根據其元素的自然排序進行排序
- TreeSet(Comparator compartor):根據指定的比較器進行排序。
(1)底層原理:
TreeSet實現了繼承於Set介面的SortedSet介面,支援自然排序和定製排序,
(2)無序且可排序(自然排序)、不可重複的,無索引,查詢快。
(3)沒有帶索引,不能使用普通for迴圈比遍歷
使用場景:
需要排序時使用。
HashSet和TreeSet的區別
49.HashSet和TreeSet有什麼區別?
相同點:1、單列儲存 2、元素不可重複
不同點:1、底層資料結構不同(HashSet=雜湊表結構 TreeSet=二叉樹結構)
2、資料唯一性依據不同(HashSet通過重寫hashcode和equals TreeSet通過compareable介面)
3、有序性不同,HashSet無序,TreeSet有序
LinkedHashSet:E表示集合中儲存的元素型別
- 特點:
- (1)底層原理:作為HashSet的子類,比它多了一條連結串列,這條鏈用來記錄元素順序。雜湊表和連結串列實現Set介面。
- (2)有序的(按輸入的順序排序由連結串列保證)、不可重複的(有雜湊表保證),無索引、查詢快
package com.guoba.day1215.arraylist.Demo;
import java.util.HashSet;
import java.util.LinkedHashSet;
/*
需求:
建立一個儲存學生物件的集合,儲存三個學生物件,
使用程式實現在控制檯遍歷集合
要求:
學生物件的成員變數相同,我們就認為是同一個物件
思路:
1.定義學生類
2.建立hashset集合物件
3.建立學生物件
4.把學生新增到集合
5.遍歷集合(增強for迴圈實現)
6.在學生類中重寫兩個方法equals和hashcode
*/
public class LinkedHashSetDemo {
public static void main(String[] args) {
Student student1 = new Student("張三",18);
Student student2 = new Student("李四",19);
Student student3 = new Student("張三",18);
LinkedHashSet<Student> linkedHashSet = new LinkedHashSet<Student>();
linkedHashSet.add(student1);
linkedHashSet.add(student2);
linkedHashSet.add(student3);
for (Student s : linkedHashSet) {
System.out.println(s.toString());//需要重寫hashcode和equals
}
}
}
package com.guoba.day1215.arraylist.Demo;
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = 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;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
if (age != student.age) return false;
return name != null ? name.equals(student.name) : student.name == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
@Override
public String toString() {
return "姓名:" + name + "\t" +
"年齡:" + age;
}
}
併發修改異常
- ConcurrentModfication
- 產生原因
- 迭代器遍歷過程中,通過集合物件修改了集合中的元素長度,造成了迭代器元素 中判斷預期修改值和實際修改值不一致。
- 解決方案
- 用for迴圈遍歷,然後用集合物件做對應的操作即可
常見資料結構之棧
- 資料進入棧模型的過程稱為:壓/進棧
- 資料離開棧模型的過程稱為:彈/出棧
- 棧是一種資料先進後出的模型
常見的資料結構之佇列
- 資料從後端進入佇列的模型稱為:入佇列
- 資料從前端離開佇列模型的過程稱為:出佇列
常見的資料結構之陣列
- 查詢資料通過索引定位
- 查詢任意資料耗時相同
- 查詢效率高
- 刪除資料時,要將原始資料刪除,
- 同時後面每個資料遷移,
- 刪除效率低
- 新增資料時,新增位置後的每個資料前移,
- 新增效率極低
雙向連結串列
2.4泛型
2.5Map
HashMap
鍵值對形式存資料。
用法:
(1)存值:put(key,value);
(2)獲取所有鍵:keySet();
(3)通過鍵獲取值get(key);
(4)移除整行資料:remove();
(5)集合長度:size();
(6)清空:clear();
步驟:
1.建立Map集合
2.存值map.put();
3.Set keys = map.keySet();//獲取所有鍵
4.Iterator
Set<Map.Entry<Key,Value>> entrySet();//Map介面方法
特點:
1.用於儲存對映關係資料
2.鍵值對(key,value)形式儲存
3.key值不重複,value可重複,且可為null;
4.不儲存基本型別資料,存物件。
5.是頂級介面,與Collection是不同體系
使用場景:
適用於Map中插入,刪除和定位元素
hashTable
- key不可重複,value可重複
- 底層雜湊表
- key和value均不能為null
hashMap和hashTable的區別
- 1.hashmap允許出現空值
- 2.執行緒非同步,效率較高
- 繼承自AbstarctMap
- 1.hashtable不允許出現空值,空鍵
- 2.執行緒同步,效率低
TreeMap
特點
(1)key不可重複,value可重複
(2)底層二叉樹
使用場景:
- 適用於按自然是內需或自定義順序遍歷鍵(key)
雜湊表
雜湊表
- 底層採用陣列+連結串列實現,可以說視一個元素為連結串列的陣列。
- 原理:先將要存的資料計算雜湊值,若雜湊表為初始化,則先初始化,
- 然後用雜湊值對陣列長度取餘,取餘得到的值就是要儲存的陣列的位置。
- 然後判斷此位置是否存在元素,若存在則比較雜湊值,
- 雜湊值不同則儲存,若不存在元素,則直接儲存。
- 若雜湊值不同則用equals判斷,若字串內容相同,
- 則不儲存,若不同則儲存。
- 從而確保了儲存元素的唯一性。
案例:hashset集合儲存學生物件並遍歷
package com.guoba.day1215.arraylist.Demo;
import java.util.HashSet;
/*
需求:
建立一個儲存學生物件的集合,儲存三個學生物件,
使用程式實現在控制檯遍歷集合
要求:
學生物件的成員變數相同,我們就認為是同一個物件
思路:
1.定義學生類
2.建立hashset集合物件
3.建立學生物件
4.把學生新增到集合
5.遍歷集合(增強for迴圈實現)
6.在學生類中重寫兩個方法equals和hashcode
*/
public class HashSetDemo {
public static void main(String[] args) {
HashSet<Student> hashSet = new HashSet<Student>();
Student student1 = new Student("張三",18);
Student student2 = new Student("李四",19);
Student student3 = new Student("張三",18);
hashSet.add(student1);
hashSet.add(student2);
hashSet.add(student3);
for (Student s : hashSet) {
System.out.println(s.getName()+s.getAge());//需要重寫hashcode和equals
// System.out.println(s);
}
}
}
package com.guoba.day1215.arraylist.Demo;
/*
學生類
*/
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = 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;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
if (age != student.age) return false;
return name != null ? name.equals(student.name) : student.name == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
}
總結:
- 所有Java集合類都位於java.utils包中,,與Java陣列不同,Java集合不能存放基本資料型別,而只能存放物件
- Java集合類主要由兩個介面派生而出,即Collection和Map介面。Collection和Map都是Java集合最頂層的父介面,這兩個介面包含其他的子介面和實現類。
- List集合代表一個元素是有序的、且可以重複的、可以為null的集合。可以通過get(int index)取出下標為index的元素。
- List最常見的實現類是ArrayList和LinkedList。
- 當對集合元素進行頻繁的讀取操作時,使用ArrayList效率比較高
- 當對集合元素進行頻繁增刪操作時,用LinkedList效率比較高
- Set集合不允許包含相同的元素,Set的排列順序可能與新增順序不同,set元素值可以為NUll,
- hashSet是Set介面的常用實現類,可以通過重寫equals和hashcode方法定義物件相等邏輯。
- Iterator迭代器提供了遍歷集合Collection元素的統一介面。
- Map用於儲存具有對映關係的資料。Map集合中保留著兩組值,一組值用於儲存Map裡的Key,另外一組值儲存Map的Value。且Key和Value可以為Null;
- Map介面的put用於新增一對鍵值對,用get返回鍵值對。