Java筆記(15) Collection集合-->List集合

来源:https://www.cnblogs.com/hiibird/archive/2023/04/14/17320033.html
-Advertisement-
Play Games

集合的理解和好處 數組一旦定義,長度即固定,不能修改。要添加新元素需要新建數組,然後迴圈拷貝,非常麻煩 集合可以動態保存任意多個對象,使用比較方便 提供餓了一系列方便的操作對象的方法:add、remove、set、get等 使用集合添加、刪除新元素的示意代碼,簡潔明瞭 集合主要是兩組(單列集合,雙列 ...


集合的理解和好處
數組一旦定義,長度即固定,不能修改。要添加新元素需要新建數組,然後迴圈拷貝,非常麻煩

  1. 集合可以動態保存任意多個對象,使用比較方便
  2. 提供餓了一系列方便的操作對象的方法:add、remove、set、get等
  3. 使用集合添加、刪除新元素的示意代碼,簡潔明瞭

集合主要是兩組(單列集合,雙列集合)
Collection 介面有兩個重要的子介面,List 和 Set,他們的實現子類都是單列集合,直接存放值
Map介面的實現子類 是雙列集合,存放的是K-V鍵值對
這是Collection介面下體系的主要介面和類體系:
Collection集合體系
這是Map介面下體系的主要介面和類體系:
Map集合體系

1. Collection介面和常用方法

1.1 Collection介面實現類的特點

public interface Collection<E> extends Iterable<E>
  1. collection實現子類可以存放多個元素,每個元素可以是Object
  2. 有些Collection的實現類,可以存放重覆的元素,有些不可以
  3. 有些Collection的實現類,有些事有序的(List),有些不是有序的(Set)
  4. Collection介面沒有直接的實現子類,是通過他的子介面Set和List來實現的

1.2 Collection介面和常用方法

以實現子類ArrayList來演示

void add(E e);        //添加單個元素, E是泛型
E remove(int index);     //刪除並返回指定元素
boolean contains(Object o);   //查找某個元素是否存在
int size();       //獲取元素個數
boolean isEmpty();    //判斷是否為空
void clear();      //清空
boolean addAll(Collection<? extends E> c);   //添加E集合中的所有元素
boolean containsAll(Collection <?> c);  //查找E集合中的元素是否都存在於該集合中
boolean removeAll(Collection<?> c);    //移除該集合中所有同時存在於E集合中的元素

1.3 Collection介面遍歷元素方式

1.3.1 使用Iterator(迭代器)

  1. Iterator對象稱為迭代器,主要用於遍歷Collection集合中的元素
  2. 所有實現了Collection介面的集合類多有一個iterator()方法,用於返回一個實現了Iterator介面的對象,即可以返回一個迭代器
  3. Iterator的方法和執行原理:
//hasNext();    判斷是否還有下一個元素
//next();       1.指針下移,2.將下移以後集合位置上的元素返回
//remove();     從底層集合中移移除此迭代器返回的最後一個元素,每次調用next()時,只能調用此方法一次。並且如果在迭代過程中,調用了除該方法意外的任何方式修改基礎集合,都會破壞迭代器,從而終止迭代,這是為了應對併發問題,因此可以通過實現此方法的時候指定併發修改策略來避免破壞迭代器。

Iterator iterator = coll.iterator();//得到一個集合的迭代器
while(iterator.hasNext()){
    //next():
    System.out.println(iterator.next());
}
  1. Iterator僅用於遍歷集合,Iterator本身並不存放對象
    提示:在調用iterator.next()方法之前,必須要調用iterator.hasNext()進行檢測。否則當下一條記錄無效時,調用iterator.next()會拋出NoSuchElementException異常。如果需要再次遍歷,需要重置迭代器:iterator=coll.iterator();

1.3.2 使用增強for迴圈

增強for迴圈的底層仍然是迭代器,所以可以理解成簡化版的迭代器
增強for迴圈可以用來遍曆數組或者Collection集合

for(element:list){
    System.out.println(element);
}

2. List介面和常用方法

List介面和Set介面都繼承了Collection介面,因此Collection介面的所有方法,實現了List介面和Set介面的類都擁有,但List介面和Set介面是平級的,因此List介面的方法,Set介面不一定擁有

2.1 List集合基本介紹

  1. List集合類中元素有序(即添加順序和取出順序一致)、且元素可重覆。
  2. List集合中每個元素都有器對應的順序索引,即支持索引。
  3. List容器中的元素都對應一個整數型的序號記載器在容器中的位置,可以根據序號存取容器中的元素
  4. JDK API中List介面的實現類有:AbstractList,AbstractSequentialList , ArrayList , AttributeList , CopyOnWriteArrayList , LinkedList , RoleList , RoleUnresolvedList , Stack , Vector

2.2 List介面的常用方法

List集合里添加了一些根據索引來操作集合元素的方法:

1. void add(int index, E element); //在index位置插入E類型的元素,E是泛型
2. boolean addAll(int index, Collection<? extends E> c); //將c中所有的元素插入index位置,c是實現了Collection介面的E類型的子類
3. E get(int index); //獲取並返回index位置的元素
4. int indexOf(Object o);   //返回obj在集合中首次出現的位置
5. int lastIndexOf(Object o);   //返回obj在集合中最後出現的位置
6. boolean remove(Object o);    //移除指定元素
7. E remove(int index); //移除並返回指定位置的元素
8. E set(int index, E element); // 返回index位置的元素,並將此位置元素替換為element
9. List<E> subList(int fromIndex, int toIndex);//返回從fromIndex到toIndex位置的前閉後開子集合[fromIndex,toIdex)

2.3 ArrayList的註意事項

ArrayList類定義說明:

public class ArrayList<E> extends AbstractList<E>
    implements List<E>, RandomAccess, Aloneable, java.io.Serializable
  1. ArrayList 可以放入null,並且可以放入多個
  2. ArrayList是由數組來實現數據存儲的
  3. ArrayList基本等同於Vector,ArrayList的執行效率更高,但是線程不安全的,因此多線程情況下,不建議使用ArrayList
    //ArrayList源碼中,沒有關於線程式控制制的代碼
    public boolean add(E e) {
        modCount++;
        add(e, elementData, size);
        return true;
    }
    //Vector源碼中使用Synchronized關鍵字修飾,是線程安全的
    public synchronized boolean add(E e) {
        modCount++;
        add(e, elementData, elementCount);
        return true;
    }
    //LinkedList也是線程不安全的
    public boolean add(E e) {
        linkLast(e);
        return true;
    }

2.4 ArrayList的底層操作機制源碼分析

  1. ArrayList中維護了一個Object類型的數組elementData
    //transient 關鍵字表示此數組不會被序列化
    transient Object[] elementData; // non-private to simplify nested class access
  1. 當創建對象時,如果使用的是無參構造器,則初始elementData容量為0.
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
  1. 當添加元素時:先判斷是否需要擴容,如果需要擴容,則調用grow方法,否則直接添加元素到適當位置
  2. 如果使用的是無參構造器,則第一次添加,需要擴容的話,則擴容elementData為10,如果需要再次擴容的話,則擴容elementData為1.5倍
  3. 如果使用的時指定容量capacity的構造器,則初始elementData的容量為capacity
  4. 如果使用的是指定容量capacity的構造器,如果需要擴容,則直接擴容elementData為1.5倍

2.5 ArrayList無參構造器

1. 使用無參構造器初始化一個數組:
ArrayList<Object> list = new ArrayList<Object>();
-->初始化過程調用過程:
-->ArrayList.java
    這一步涉及的成員變數:
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    //首先將elementData初始化為空數組
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
2. 迴圈添加數據:
for(int i = 1; i <= 10; i++){
    list.add(i);
}
-->調用過程:
-->ArrayList.java
    這一步涉及的成員變數:
    private int size; //成員變數,用來記錄數組列表的大小(包含元素的數量)
    private static final int DEFAULT_CAPACITY = 10;
    
    //首先發生int->Integer自動裝箱
    //然後調用 boolean add(E e)方法,modCount記錄該集合被修改的次數
    public boolean add(E e) {
        modCount++;
        add(e, elementData, size);//size = 0
        return true;
    }
        --> private void add(E e, Object[] elementData, int s) {
                if (s == elementData.length)//如果當前數組已滿
                    elementData = grow();//調用grow函數擴容至10
                elementData[s] = e;
                size = s + 1;
        }
        --> Object[] grow(){
            return grow(size+1);
        }
        --> Object[] grow(int minCapacity){//將數組拷貝到長度為10的新數組中
            return elementData = Arrays.copyOf(elementData, newCapacity(minCapacity));
        }
        --> int newCapacity(int minCapacity){    //return 10;
            int oldCapacity = elementData.length;
            int newCapacity = oldCapacity + (oldCapacity>>1);//新容量為舊容量的(1+0.5)倍
            if(newCapacity - minCapacity <= 0){//即如果舊容量為0或1
                //如果當前數組為就是那個空的成員數組,就返回10和(當前容量+1)中較大的一個
                if(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDTA){
                    return Math.max(DEFAULT_CAPACITY,minCapacity);
                }
                //block of code unrelated to the operation
            }
        }
3. 再次迴圈添加數據:
for (int i = 11; i <= 15; i++){
    list.add;
}
-->調用過程:
-->ArrayList.java
    public boolean add(E e) {
        modCount++;
        add(e, elementData, size);
        return true;
    }
    --> private void add(E e, Object[] elementData, int s) {
        if (s == elementData.length)//此時數組已經存滿了
            elementData = grow();//調用grow方法再次擴容至10*(1+0.5)=15
        elementData[s] = e; //在第10位存入這一輪的數據
        size = s + 1;
    }
    --> private Object[] grow() {
        return grow(size + 1);//size = 10
    }
    --> private Object[] grow(int minCapacity) {//minCapacity = 11,即最小也得11個位置才可以,新數組不能小於這個數
        return elementData = Arrays.copyOf(elementData,
                                           newCapacity(minCapacity));
    }
    --> private int newCapacity(int minCapacity) {//minCapacity = 11
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);//15
        if (newCapacity - minCapacity <= 0) {//false
            if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
                return Math.max(DEFAULT_CAPACITY, minCapacity);
            if (minCapacity < 0) // overflow //false
                throw new OutOfMemoryError();
            return minCapacity; //return 15
        }
        return (newCapacity - MAX_ARRAY_SIZE <= 0)
            ? newCapacity
            : hugeCapacity(minCapacity);
    }
4. 再次添加數據:
list.add(100);//此時由於list.length = 15,容量已經滿了,會再次擴容至22
//

2.5 Vector的基本介紹

  1. Vector類的定義說明
public class Vector<E>
    extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable
  1. Vector 底層也是一個對象數組,protected Object[] elementData;
  2. Vector是線程同步的,即線程安全,Vector類的操作方法帶有synchronized
public synchronized void setSize(int newSize) {
    modCount++;
    if (newSize > elementData.length)
        grow(newSize);
    final Object[] es = elementData;
    for (int to = elementCount, i = newSize; i < to; i++)
        es[i] = null;
    elementCount = newSize;
}
  1. 在開發中,需要線程同步安全時,考慮使用Vector

2.5.1 Vector和ArrayList的比較

集合 底層結構 版本 線程安全(同步)效率 擴容
ArrayList 可變數組 jdk1.2 不安全,效率高 如果有參構造,1.5倍;如果是無參構造,第一次10,從第二次開始按1.5倍擴容
Vector 可變數組 jdk1.0 安全,效率不高 如果是無參,預設10,滿後按2倍擴容;有參構造則按指定大小創建,並每次按2倍擴容,也可以手動指定增量capacityIncrement,每次增加capacityIncrement

2.6 LinkedList

LinkedList類定義說明

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable
  1. LinkedList實現了雙向鏈表和雙端隊列特點
  2. 可以天界任意元素(元素可以重覆),包括null
  3. 線程不安全,沒有實現同步

2.6.1 LinkedList底層架構

LinkedList的底層操作機制

  1. LinkedList底層維護了一個雙向鏈表。
  2. LinkedLsit中維護了兩個屬性first和last分別指向首節點和尾節點
  3. 每個節點(Node對象)裡面又維護了prev、next、item三個屬性,其中通過prev指向前一個,通過next指向後一個節點,最終實現雙向鏈表。
  4. 所以LinkedList的元素的添加和刪除,不是通過數組完成的,相對來說效率較高

2.6.1 ArrayList和LinkedList比較

集合 底層結構 增刪的效率 改查的效率
ArrayList 可變數組 較低 較高
LinkedList 雙向鏈表 較高,通過鏈表追加 較低

2.6.2 如何選擇ArrayList和LinkedList

  1. 如果改查的操作多,選擇ArrayList
  2. 如果增刪的操作多,選擇LinkedList
  3. 一般來說,在程式中,80%~90%的操作都是查詢,因此大部分情況下會選擇ArrayList
  4. 在一個項目中,根據業務靈活選擇,也可能這樣,一個模塊使用的是ArrayList,另一個模塊使用的是LinkedList,要根據業務來選擇。
  5. 這兩個都是線程不安全的,在單線程程式中使用

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 前端開發者若要進行後端開發,大多都會選擇node.js,在node生態下是有大量框架的,其中最受新手喜愛的便是老牌的express.js,接下來我們就從零創建一個express項目。 安裝node 在這裡:https://nodejs.org/dist/v16.14.0/node-v16.14 ...
  • 作者羅錦華,API7.ai 技術專家/技術工程師,開源項目 pgcat,lua-resty-ffi,lua-resty-inspect 的作者。 原文鏈接 為什麼需要 Lua 動態調試插件? Apache APISIX 有很多 Lua 代碼,如何在運行時不觸碰源代碼的情況下,檢查代碼裡面的變數值? ...
  • 和女朋友坐一塊的時候,突然想到了,哈哈哈哈哈 不會很難!!! import java.util.*; import java.lang.Math; // 註意類名必須為 Main, 不要有任何 package xxx 信息 public class Main { public static void ...
  • Flask-SQLAlchemy MySQL是免費開源軟體,大家可以自行搜索其官網(https://www.MySQL.com/downloads/) 測試MySQL是否安裝成功 在所有程式中,找到MySQL→MySQL Server 5.6下麵的命令行工具,然後單擊輸入密碼後回車,就可以知道MyS ...
  • 前言 在上一篇文章中,我們介紹了~運算符的高級用法,本篇文章,我們將介紹<< 運算符的一些高級用法。 一、人物簡介 第一位閃亮登場,有請今後會一直教我們C語言的老師 —— 自在。 第二位上場的是和我們一起學習的小白程式猿 —— 逍遙。 二、計算2的整數次冪 代碼示例 #include <stdio. ...
  • 布隆過濾器是一個精巧而且經典的數據結構。 你可能沒想到: RocketMQ、 Hbase 、Cassandra 、LevelDB 、RocksDB 這些知名項目中都有布隆過濾器的身影。 對於後端程式員來講,學習和理解布隆過濾器有很大的必要性。來吧,我們一起品味布隆過濾器的設計之美。 1 緩存穿透 我 ...
  • Java + Jpcap實現監控 IP包流量 說明:本設計是電腦網路課程的課設,因為代碼是提前實現的,本博客於後期補上,又因為代碼沒寫註釋自己也看不懂了,所以,僅供參考,就當提供一種實現方式。 文中提供的《Jpcap中文API文檔》來源於網路,本文僅用於學習交流,如有侵權,可聯繫我進行刪除。 效果 ...
  • 是什麼 迴圈隊列, FIFO先進先出 怎麼用 初始化 //C11 deque<int> deq{1,2,3,4,5}; //拷貝構造,可以拷貝deque queue<int> que(deq); //100個5 queue<int> que2(100,5); //運算符重載 que2 = que; ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...