1. 程式人生 > 其它 >最全的集合筆記(乾貨)

最全的集合筆記(乾貨)

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 list = new ArrayList();//建立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 it = keys.iterator();//迭代器遍歷hasNext(),next()

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返回鍵值對。