日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

Java 集合

發(fā)布時(shí)間:2025/6/15 java 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java 集合 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
java集合

fail-fast機(jī)制

在java集合類(lèi)中,使用modCount來(lái)檢查數(shù)組的狀態(tài).
當(dāng)在迭代集合的時(shí)候,(通常會(huì)實(shí)現(xiàn) iterator()方法來(lái)獲取迭代對(duì)象,或者 foreach),
集合里面的數(shù)據(jù),在其他地方被修改了,這個(gè)時(shí)候 modCount就會(huì)被修改,與迭代過(guò)程的modCount不一致.將拋出ConcurrentModificationException異常,這個(gè)過(guò)程就叫 fail-fast

List 篇

主要介紹 ArrayList,Vector和LinkedList,CopyOnWriteArrayList


ArrayList

是一個(gè)數(shù)組長(zhǎng)度可自增長(zhǎng)的線程不安全的列表.內(nèi)部使用數(shù)組實(shí)現(xiàn). Object[] elementData.

  • 默認(rèn)的長(zhǎng)度為 10.
  • fail-fast
  • 自動(dòng)擴(kuò)容(每次擴(kuò)容為原來(lái)的1.5倍)
  • 線程不安全
  • 使用連續(xù)控件存儲(chǔ)
  • 繼承自 List,RandomAccess等.
  • 允許添加 null值
  • 時(shí)間復(fù)雜度 :

    根據(jù)索引查詢(xún),復(fù)雜度為 O(1).
    根據(jù)元素查詢(xún),復(fù)雜度為 O(N).
    插入和刪除,如果在列首復(fù)雜度為 O(N);在列尾復(fù)雜度為 O(1);平均復(fù)雜為 O(N)

    插入和刪除非列尾數(shù)據(jù), 將會(huì)導(dǎo)致數(shù)組移動(dòng)數(shù)據(jù).

    RandomAccess 接口

    RandomAccess 是一個(gè)標(biāo)記接口(沒(méi)有任何方法).
    如果實(shí)現(xiàn)了 RandomAccess 接口,表示該集合可以進(jìn)行隨機(jī)快速訪問(wèn)(通常底層是 數(shù)組形式的集合),如 ArrayList.
    可以快速訪問(wèn)的集合,使用

    for (int i=0, n<size; i++)list.get(i);

    未實(shí)現(xiàn) RandomAccess接口的集合,如LinkedList,使用迭代器效率更高.

    for (Iterator i=list.iterator(); i.hasNext(); )i.next();

    使用 instanceof RandomAccess來(lái)判斷是否 支持隨機(jī)快速訪問(wèn).

    Vector

    是一個(gè)數(shù)組長(zhǎng)度可自增長(zhǎng)的線程安全的列表,內(nèi)部使用數(shù)組實(shí)現(xiàn).

  • 默認(rèn)的長(zhǎng)度為 10.
  • fail-fast
  • 自動(dòng)擴(kuò)容(可設(shè)置每次擴(kuò)容的增量值,默認(rèn)擴(kuò)容為原來(lái)的2倍.)
  • 線程安全(synchronized)
  • 使用連續(xù)控件存儲(chǔ)
  • 繼承自 RandomAccess,List
  • 允許添加 null值
  • 線程安全的vector,照樣可以觸發(fā) fail-fast.
    時(shí)間復(fù)雜度與 arraylist 一樣.

    在不涉及線程安全的前提下,arraylist效率更高.

    fun main(args: Array<String>) {val vector = Vector(listOf(1, 2, 3, 4, 5))singleThread(vector)multiThread(vector)multiThreadSynchronized(vector) }/*** 單線程下,迭代拋出 ConcurrentModificationException*/ fun singleThread(vector: Vector<Int>) {val it = vector.iterator()while (it.hasNext()) {println(it.next())vector.add(1)} }/*** 多線程下,迭代拋出 ConcurrentModificationException*/ fun multiThread(vector: Vector<Int>) {thread {repeat(10000) {vector.add(it)}}thread {vector.forEach { println(it) }} }/*** 多線程下,修改vector是添加同步鎖,避免同時(shí)迭代同時(shí)修改*/ fun multiThreadSynchronized(vector: Vector<Int>) {thread {synchronized(vector) {repeat(10000) {vector.add(it)}}}thread {vector.forEach { println(it) }} }

    Stack

    繼承自 vector,線程安全,棧結(jié)構(gòu),先進(jìn)后出.

    LinkedList

    是以雙向鏈表方式實(shí)現(xiàn)的非線程安全的集合.

  • 一個(gè)元素節(jié)點(diǎn)包含 上一個(gè)節(jié)點(diǎn)和下一個(gè)節(jié)點(diǎn)的引用,以及自身的值.
  • 內(nèi)存空間可不連續(xù)
  • 線程不安全
  • fail-fast
  • 繼承自 List,Deque等.
  • 允許添加 null值
  • 時(shí)間復(fù)雜度:

    刪除和插入元素,復(fù)雜度為 O(1).
    查詢(xún)時(shí),由于采用雙向鏈表,判斷離哪頭近,從哪頭開(kāi)始找.
    最糟糕的情況是O(N/2),所以它的復(fù)雜度為 O(N).

    CopyOnWriteArrayList

    CopyOnWriteArrayList是并發(fā)包中的實(shí)現(xiàn).使用 ReenterLock和System.arraycopy來(lái)實(shí)現(xiàn)數(shù)組讀寫(xiě)的線程安全.

    在讀取的時(shí)不加鎖,所以可以支持多線程同時(shí)讀取數(shù)據(jù),并且同時(shí)讀取數(shù)不受限制.

    在寫(xiě)入(add,set,remove等操作)的時(shí)候,使用 ReenterLock鎖住方法,然后操作數(shù)據(jù)時(shí)先將原數(shù)組拷貝一份,對(duì)拷貝數(shù)據(jù)進(jìn)行操作,操作完后將拷貝的原來(lái)的數(shù)據(jù)引用指向拷貝的數(shù)組引用,實(shí)現(xiàn)數(shù)據(jù)的更新操作,更新完后釋放鎖. 和其名字操作一致(寫(xiě)時(shí)拷貝).

    沒(méi)有設(shè)置初始長(zhǎng)度的方法和擴(kuò)容的策略. 因?yàn)樵摂?shù)組在每次 添加數(shù)據(jù)是, 都會(huì)使用 System.arraycopy拷貝一份比當(dāng)前數(shù)據(jù) +1 的數(shù)組.

    public boolean add(E e) {final ReentrantLock lock = this.lock;lock.lock();try {Object[] elements = getArray();int len = elements.length;Object[] newElements = Arrays.copyOf(elements, len + 1);newElements[len] = e;setArray(newElements);return true;} finally {lock.unlock();}}

    ArrayList,Vector和LinkedList的區(qū)別

    ArrayList和Vector內(nèi)部都是使用數(shù)組實(shí)現(xiàn)的.它們的主要區(qū)別在于

  • ArrayList 是線程不安全的,Vector是線程安全的.
  • ArrayList 自動(dòng)擴(kuò)容時(shí)固定增長(zhǎng)為原來(lái)的1.5倍,不可指定增量值. Vector可指定每次的增量值,如果沒(méi)指定,則擴(kuò)容為原來(lái)的2倍.
  • 在不考慮線程安全的情況下,優(yōu)先使用 ArrayList,如果在使用前,能夠預(yù)估大概有元素,創(chuàng)建時(shí)指定個(gè)數(shù),效果更好.

    LinkedList 使用雙向鏈表實(shí)現(xiàn),也是線程不安全的.與ArrayList的區(qū)別在于

  • 實(shí)現(xiàn)方式不同.ArrayList使用數(shù)組,Vector使用雙向鏈表.
  • 內(nèi)存空間管理不同,LinkedList可以是不連續(xù)的空間,ArrayList需要連續(xù)的內(nèi)存空間.
  • LinkedList 在刪除和插入上的性能較好, ArrayList在查詢(xún)上的效率更好.
  • ArrayList 一個(gè)item只存自己的值,比較省空間, LinkedList一個(gè)item除了自己的值,還需要存放上一個(gè)和下一個(gè)元素的引用,比較費(fèi)空間.
  • 如果主要需要對(duì)列表進(jìn)行遍歷,以及增刪操作,使用LinkedList其他情況使用ArrayList.

    如果需要用到線程安全的列表,請(qǐng)使用 CopyOnWriteArrayList

    Map篇

    Map 是以鍵值對(duì)形式存儲(chǔ)的集合.

    主要介紹 HashMap,TreeMap和 Hashtable,ConcurrentHashMap


    HashMap

    HashMap 內(nèi)部混合使用數(shù)組,鏈表,紅黑樹(shù)的結(jié)構(gòu)來(lái)構(gòu)建的鍵值對(duì)集合.

    HashMap的本質(zhì)基礎(chǔ)是基于數(shù)組的. 數(shù)組的各個(gè)元素,使用單向鏈表的結(jié)構(gòu).(Node(int hash, K key, V value, Node<K,V> next)).

    HashMap通過(guò)哈希函數(shù)(hash())來(lái)完成key對(duì)index的映射.

    當(dāng)出現(xiàn)hash后index沖突(index位置已經(jīng)存在不同的key的鍵值對(duì))時(shí),數(shù)據(jù)將在index位置,使用單向鏈表或紅黑樹(shù)(當(dāng)鏈表長(zhǎng)度大于等8個(gè)時(shí),鏈表中的所有元素改用紅黑樹(shù)存放)來(lái)存放元素.

    當(dāng)使用掉的索引 占用了 數(shù)組長(zhǎng)度的一定比例時(shí)(填裝因子),HashMap將進(jìn)行擴(kuò)容(擴(kuò)容為原來(lái)的兩倍,key與index重新映射).

    HashMap的性能瓶頸:

  • 優(yōu)良的 哈希函數(shù).
  • 理想的狀態(tài)是,每一個(gè)鍵值對(duì)的存放,能夠比較均勻適當(dāng)?shù)姆植荚跀?shù)組的索引上,盡量避免過(guò)多的hash值沖突.

    // java 8 中的實(shí)現(xiàn)static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);} // index = (n - 1) & hash , 2的次方來(lái)說(shuō)就是取余操作. // 由于 (n -1)的二進(jìn)制 高位都是0,地位都是1. // hashcode 與 它進(jìn)行 & 操作的話, hashcode的高位變化低位不變,則計(jì)算出來(lái)的index值講不變. // 為了消除高位變化 不影響 index 的值, 于是將 hashcode 的 高16位 移動(dòng)到低16位,再和 hashcode進(jìn)行 ^ 操作. // 這樣高位的變化,也能影響index值, 降低了沖突的概率.
  • 填裝因子
  • 過(guò)低的填裝因子,如填裝因子=0.5,容量剩余一半的時(shí)候就擴(kuò)容,可能導(dǎo)致空間上的浪費(fèi).
    過(guò)高的填裝因子,可能導(dǎo)致為了命中未使用的索引,而頻繁出現(xiàn) 沖突.
    HashMap實(shí)現(xiàn)中,填裝因子默認(rèn)使用 0.75的值.

    特點(diǎn) :

  • 默認(rèn)的長(zhǎng)度為 16,默認(rèn)填裝因子為 0.75.
  • fail-fast
  • 自動(dòng)擴(kuò)容(默認(rèn)擴(kuò)容為原來(lái)的2倍.)
  • 線程不安全
  • 混合使用數(shù)組,鏈表和紅黑樹(shù)
  • 繼承自Map
  • key和value都可以添加 null
  • 插入和遍歷順序不一致
  • 時(shí)間復(fù)雜度 :

    查詢(xún),插入和刪除操作的平均時(shí)間復(fù)雜度為 O(1).
    極端情況下(全部發(fā)生沖突),若長(zhǎng)度小于8,使用單項(xiàng)鏈表,復(fù)雜度為 O(n),如果長(zhǎng)度大于等于8,使用紅黑樹(shù),復(fù)雜度為O(logn)

    LinkedHashMap

    繼承自 HashMap, 底層使用哈希表與雙向鏈表來(lái)保存元素,與HashMap的差異就在于 訪問(wèn)順序上.
    構(gòu)造中,accessOrder 默認(rèn)為 false,代表按照插入順序進(jìn)行迭代;為 true,代表以訪問(wèn)順序進(jìn)行迭代(最常訪問(wèn)的在前,最不經(jīng)常訪問(wèn)的在后LRU)。

    TreeMap

    TreeMap內(nèi)部使用 紅黑樹(shù)來(lái)實(shí)現(xiàn)的鍵值對(duì)集合.與HashMap相比,TreeMap是一個(gè)能比較元素大小的Map集合,會(huì)對(duì)傳入的key進(jìn)行了大小排序。其中,可以使用元素的自然順序,也可以使用集合中自定義的比較器來(lái)進(jìn)行排序.

    特點(diǎn) :

  • fail-fast
  • 線程不安全
  • 使用紅黑樹(shù)實(shí)現(xiàn)
  • key和value都可以添加 null
  • 插入和遍歷順序不一致
  • 支持對(duì)key排序
  • 繼承自NavigableMap,擁有強(qiáng)大的搜索功能.
  • 時(shí)間復(fù)雜度 :

    紅黑樹(shù)是自平衡的二叉搜索樹(shù), 查詢(xún),添加刪除 效率都是 O(logn).

    HashTable

    HashTable 內(nèi)部使用數(shù)組和單項(xiàng)鏈表實(shí)現(xiàn)的鍵值對(duì)集合.

    HashTable的哈希函數(shù) (hash & 0x7FFFFFFF) % tab.length,只是對(duì)key的hashcod進(jìn)行取整和取余操作.

    HashTable默認(rèn)的初始大小為11,之后每次擴(kuò)充為原來(lái)的2n+1。
    也就是說(shuō),HashTable的鏈表數(shù)組的默認(rèn)大小是一個(gè)素?cái)?shù)、奇數(shù)。之后的每次擴(kuò)充結(jié)果也都是奇數(shù)。
    由于HashTable會(huì)盡量使用素?cái)?shù)、奇數(shù)作為容量的大小。當(dāng)哈希表的大小為素?cái)?shù)時(shí),簡(jiǎn)單的取模哈希的結(jié)果會(huì)更加均勻。(這個(gè)是可以證明出來(lái) 的,可參考:http://zhaox.github.io/algorithm/2015/06/29/hash)

    特點(diǎn) :

  • 默認(rèn)的長(zhǎng)度為 11,默認(rèn)填裝因子為 0.75.
  • fail-fast
  • 自動(dòng)擴(kuò)容(擴(kuò)容為原來(lái)的2n+1)
  • 線程安全
  • 混合使用數(shù)組,鏈表
  • 繼承自Map
  • key和value都不能使用null值,否則拋出空指針異常.
  • 插入和遍歷順序不一致
  • 時(shí)間復(fù)雜度 :

    和HashMap一致

    ConcurrentHashMap (java.util.concurrent)

    和HashMap一樣,是內(nèi)部使用數(shù)組,鏈表,紅黑樹(shù)的結(jié)構(gòu)來(lái)構(gòu)建的鍵值對(duì)集合,因?yàn)樾枰WC線程安全,所以?xún)?nèi)部實(shí)現(xiàn)更加復(fù)雜.

    哈希函數(shù) (h ^ (h >>> 16)) & HASH_BITS , 和HashMap類(lèi)似,與高位進(jìn)行異或操作的方式,來(lái)消除高位數(shù)據(jù)變化導(dǎo)致索引不變的情況,多加了一步正數(shù)的操作.

    當(dāng)沖突的鏈表中個(gè)數(shù)超過(guò)8個(gè), 如果數(shù)組長(zhǎng)度小于64,則擴(kuò)容,否則,將鏈表數(shù)據(jù)轉(zhuǎn)化為 紅黑樹(shù)結(jié)構(gòu)存儲(chǔ).

    ConcurrentHashMap 采用 CAS(Compare and Swap)原子類(lèi)型操作,來(lái)保證線程的安全性. 較 jdk1.7 的分段鎖機(jī)制性能更好.

    特點(diǎn) :

  • 默認(rèn)長(zhǎng)度為16,無(wú)默認(rèn)的裝填因子
  • 構(gòu)造函數(shù)為 : ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel)
    沒(méi)有默認(rèn)的裝填因子,傳入 初始容量和裝填因子后,會(huì)被算法調(diào)整為 2次方,最小容量為 16.
    并發(fā)級(jí)別,表示 可以同時(shí)對(duì)數(shù)據(jù)進(jìn)行寫(xiě)操作的線程數(shù), 最大可達(dá)16. 讀取不受限制.

  • 沒(méi)有 fail-fast, 將保證線程安全.
  • 自動(dòng)擴(kuò)容為原來(lái)的 2 倍.
  • 線程安全
  • 混合使用數(shù)組,鏈表和紅黑樹(shù)
  • 繼承自ConcurrentMap
  • key和value都可以添加 null
  • 插入和遍歷順序不一致
  • 時(shí)間復(fù)雜度 :

    和HashMap一致

    HashMap和HashTable , ConcurrentHashMap對(duì)比

    HashMap 線程不安全 , HashTable線程安全,但還是存在fail-fast問(wèn)題 , ConcurrentHashMap線程安全,不存在fail-fast問(wèn)題.

    HashMap 和 ConcurrentHashMap 內(nèi)部都是用 數(shù)組,鏈表 加紅黑樹(shù)來(lái)構(gòu)建.(較高效) HashTable 使用數(shù)組加鏈表.

    HashMap 和 ConcurrentHashMap 都是用 高位異或的哈希算法. HashTable 采用 數(shù)組長(zhǎng)度為素?cái)?shù),直接取余的哈希算法.

    HashMap 允許插入 null鍵值對(duì), HashTable , ConcurrentHashMap 不允許.

    結(jié)論 : 不考慮線程安全的情況下使用 HashMap, 線程安全則使用 ConcurrentHashMap.
    如果知道 大概會(huì)存多少數(shù)據(jù),指定 初始容量 會(huì)更高效, 避免擴(kuò)容和重新hash映射產(chǎn)生的效率問(wèn)題.

    Set篇

    Set 是沒(méi)有重復(fù)元素的單元素集合.

    TreeSet 內(nèi)部使用 TreeMap實(shí)現(xiàn).

    HashSet 內(nèi)部使用 HashMap實(shí)現(xiàn). 當(dāng)構(gòu)造參數(shù)為三個(gè)時(shí) LinkedHashMap實(shí)現(xiàn).

    LinkedHashSet 繼承自 HashSet,但是都是調(diào)用 HashSet中有三個(gè)構(gòu)造參數(shù)的LinkedHashMap來(lái)實(shí)現(xiàn).

    總結(jié)

    以上是生活随笔為你收集整理的Java 集合的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。