搜尋
首頁Javajava教程java初學者必備小抄

java初學者必備小抄

Dec 10, 2016 am 09:23 AM
javajava初學者

在盡可能短的篇幅裡,將所有集合與並發集合的特徵,實現方式,性能捋一遍。適合所有”精通Java”其實還不那麼自信的人閱讀。

List

ArrayList

以數組實作。節約空間,但數組有容量限制。超出限制時會增加50%容量,用System.arraycopy()複製到新的數組,因此最好能給出數組大小的預估值。預設第一次插入元素時建立大小為10的陣列。

按數組下標存取元素–get(i)/set(i,e) 的效能很高,這是數組的基本優勢。

直接在數組末尾加入元素–add(e)的效能也高,但如果按標插入、刪除元素–add(i,e), remove(i), remove(e),則要用System. arraycopy()來移動部分受影響的元素,性能就變差了,這是基本劣勢。

LinkedList

以雙向鍊錶實作。鍊錶無容量限制,但雙向鍊錶本身使用了更多空間,也需要額外的鍊錶指標操作。

按下標訪問元素–get(i)/set(i,e) 要悲劇的遍歷鍊錶將指針移動到位(如果i>數組大小的一半,會從末尾移起)。

插入、刪除元素時修改前後節點的指標即可,但還是要遍歷部分鍊錶的指標才能移動到下標所指的位置,只有在鍊錶兩頭的操作–add(), addFirst(),removeLast( )或用iterator()上的remove()能省掉指標的移動。

CopyOnWriteArrayList

並發優化的ArrayList。用CopyOnWrite策略,在修改時先複製一個快照來修改,改完再讓內部指標指向新陣列。

因為對快照的修改對讀取操作來說不可見,所以只有寫鎖沒有讀鎖,加上複製的昂貴成本,典型的適合讀多寫少的場景。如果更新頻率較高,或數組較大時,還是Collections.synchronizedList(list),對所有操作用同一把鎖來確保線程安全更好。

增加了addIfAbsent(e)方法,會遍歷數組來檢查元素是否已存在,而效能可想像的不會太好。

補充

無論哪種實現,按值返回下標–contains(e), indexOf(e), remove(e) 都需遍歷所有元素進行比較,性能可想像的不會太好。

沒有依元素值排序的SortedList,在執行緒安全類別中也沒有無鎖定演算法的ConcurrentLinkedList,湊合著用Set與Queue中的等價類別時,會缺少一些List特有的方法。

Map

HashMap

以Entry[]陣列實作的雜湊桶數組,用Key的雜湊值取模桶數組的大小可得到數組下標。

插入元素時,如果兩條Key落在同一個桶(比如哈希值1和17取模16後都屬於第一個哈希桶),Entry用一個next屬性實作多個Entry以單向鍊錶存放,後入桶的Entry將next指向桶目前的Entry。

尋找雜湊值為17的key時,先定位到第一個雜湊桶,然後以鍊錶遍歷桶裡所有元素,逐一比較其key值。

當Entry數量達到桶數量的75%時(很多文章說使用的桶數量達到了75%,但看代碼不是),會成倍擴容桶數組,並重新分配所有原來的Entry,所以這裡也最好有個預估值。

取模用位元運算(hash & (arrayLength-1))會比較快,所以陣列的大小永遠是2的N次方, 你隨便給一個初始值例如17會轉為32。預設第一次放入元素時的初始值是16。

iterator()時順著哈希桶數組來遍歷,看起來是個亂序。

在JDK8裡,新增預設8的閥值,當一個桶裡的Entry超過閥值,就不以單向鍊錶而以紅黑樹來存放以加快Key的查找速度。

LinkedHashMap

擴充HashMap增加雙向鍊錶的實現,號稱是最佔記憶體的資料結構。支援iterator()時會依照Entry的插入順序來排序(但是更新不算, 如果設定accessOrder屬性為true,則所有讀寫存取都算)。

實作上是在Entry上再增加屬性before/after指針,插入時把自己加到Header Entry的前面去。如果所有讀寫存取都要排序,還要把前後Entry的before/after拼接起來以在鍊錶中刪除掉自己。

TreeMap

以紅黑樹實現,支援iterator()時按Key值排序,可依實現了Comparable介面的Key的升序排序,或由傳入的Comparator控制。可想的,在樹上插入/刪除元素的代價一定比HashMap的大。

支援SortedMap接口,如firstKey(),lastKey()取得最大最小的key,或sub(fromKey, toKey), tailMap(fromKey)剪取Map的某一段。

ConcurrentHashMap

並發優化的HashMap,預設16把寫鎖(可以設定更多),有效分散了阻塞的機率,而且沒有讀鎖。 
資料結構為Segment[],Segment裡面才是哈希桶數組,每個Segment一把鎖。 Key先算出它在哪個Segment裡,再算出它在哪個哈希桶裡。

支援ConcurrentMap接口,如putIfAbsent(key,value)與相反的replace(key,value)與以及實現CAS的replace(key, oldValue, newValue)。

沒有讀鎖定是因為put/remove動作是個原子動作(比如put是一個對數組元素/Entry 指標的賦值操作),讀取操作不會看到一個更新動作的中間狀態。

ConcurrentSkipListMap

JDK6新增的並發優化的SortedMap,以SkipList實作。 SkipList是紅黑樹的簡化替代方案,是個流行的有序集合演算法,篇幅所限見入門教學。 Concurrent套件選用它是因為它支援基於CAS的無鎖演算法,而紅黑樹則沒有好的無鎖演算法。

很特殊的,它的size()不能隨便調,會遍歷來統計。

補充

關於null,HashMap和LinkedHashMap是隨意的,TreeMap沒有設定Comparator時key不能為null;ConcurrentHashMap在JDK7裡value不能為null(這是為什麼呢?),JDK8裡key與value都不能為null ;ConcurrentSkipListMap是所有JDK裡key與value都不能為null。

Set

Set幾乎都是內部用一個Map來實現, 因為Map裡的KeySet就是一個Set,而value是假值,全部使用同一個Object。 Set的特徵也繼承了那些內部Map實作的特徵。

HashSet:內部是HashMap。 
LinkedHashSet:內部是LinkedHashMap。 
TreeSet:內部是TreeMap的SortedSet。 
ConcurrentSkipListSet:內部是ConcurrentSkipListMap的同時最佳化的SortedSet。 
CopyOnWriteArraySet:內部是CopyOnWriteArrayList的並發優化的Set,利用其addIfAbsent()方法實現元素去重,如前所述該方法的效能很一般。 
補充:好像少了個ConcurrentHashSet,本來也該有一個內部用ConcurrentHashMap的簡單實現,但JDK偏偏沒提供。 Jetty就自己封了一個,Guava則直接用java.util.Collections.newSetFromMap(new ConcurrentHashMap()) 實作。

Queue

Queue是在兩端出入的List,所以也可以用陣列或鍊錶來實現。

–普通隊列–

LinkedList

是的,以雙向鍊錶實現的LinkedList既是List,也是Queue。它是唯一允許放入null的Queue。

ArrayDeque

以循環數組實現的雙向Queue。大小是2的倍數,預設是16。

普通數組只能快速在末尾添加元素,為了支援FIFO,從數組頭快速取出元素,就需要使用循環數組:有隊頭隊尾兩個下標:彈出元素時,隊頭下標遞增;加入元素時,如果已到數組空間的末尾,則將元素循環賦值到數組0,同時隊尾下標指向0,再插入下一個元素則賦值到數組[1],隊尾下標指向1。如果隊尾的下標追上隊頭,表示數組所有空間都已用完,進行雙倍的數組擴容。

PriorityQueue

用二元堆實現的優先權隊列,不再是FIFO而是按元素實現的Comparable接口或傳入Comparator的比較結果來出隊,數值越小,優先權越高,越先出隊。但是注意其iterator()的回傳不會排序。

–線程安全的隊列–

ConcurrentLinkedQueue/ConcurrentLinkedDeque

無界的並發優化的Queue,基於鍊錶,實現了依賴CAS的無鎖定演算法。

ConcurrentLinkedQueue的結構是單向鍊錶和head/tail兩個指針,因為入隊時需要修改隊尾元素的next指針,以及修改tail指向新入隊的元素兩個CAS動作無法原子,所以需要的特殊的演算法,篇幅所限見入門教學。

PriorityBlockingQueue

無界的並發優化的PriorityQueue,也是基於二元堆。使用一把公共的讀寫鎖。雖然實作了BlockingQueue接口,其實沒有任何阻塞佇列的特徵,空間不夠時會自動擴容。

DelayQueue

內部包含一個PriorityQueue,同樣是無界的。元素需實現Delayed接口,每次調用時需返回當前離觸發時間還有多久,小於0表示該觸發了。 
pull()時會用peek()查看隊頭的元素,檢查是否到達觸發時間。 ScheduledThreadPoolExecutor用了類似的結構。

–線程安全的阻塞隊列–

BlockingQueue的隊列長度受限,用以確保生產者與消費者的速度不會相差太遠,避免記憶體耗盡。隊列長度設定後不可改變。當入隊時隊列已滿,或出隊時隊列已空,不同函數的效果見下表: 

java初學者必備小抄

ArrayBlockingQueue

定長的並發優化的BlockingQueue,基於循環數組實現。有一把公共的讀寫鎖與notFull、notEmpty兩個Condition管理佇列滿或空時的阻塞狀態。

LinkedBlockingQueue/LinkedBlockingDeque

可選定長的並發優化的BlockingQueue,基於鍊錶實現,所以可以把長度設為Integer.MAX_VALUE。利用鍊錶的特徵,分離了takeLock與putLock兩把鎖,繼續用notEmpty、notFull管理佇列滿或空時的阻塞狀態。

補充

JDK7有個LinkedTransferQueue,transfer(e)方法保證Producer放入的元素,被Consumer取走了再返回,比SynchronousQueue更好,有空要學習下。


陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
為什麼Java是開發跨平台桌面應用程序的流行選擇?為什麼Java是開發跨平台桌面應用程序的流行選擇?Apr 25, 2025 am 12:23 AM

javaispopularforcross-platformdesktopapplicationsduetoits“ writeonce,runany where”哲學。 1)itusesbytiesebyTecodeThatrunsonAnyJvm-備用Platform.2)librarieslikeslikeslikeswingingandjavafxhelpcreatenative-lookingenative-lookinguisis.3)

討論可能需要在Java中編寫平台特定代碼的情況。討論可能需要在Java中編寫平台特定代碼的情況。Apr 25, 2025 am 12:22 AM

在Java中編寫平台特定代碼的原因包括訪問特定操作系統功能、與特定硬件交互和優化性能。 1)使用JNA或JNI訪問Windows註冊表;2)通過JNI與Linux特定硬件驅動程序交互;3)通過JNI使用Metal優化macOS上的遊戲性能。儘管如此,編寫平台特定代碼會影響代碼的可移植性、增加複雜性、可能帶來性能開銷和安全風險。

與平台獨立性相關的Java開發的未來趨勢是什麼?與平台獨立性相關的Java開發的未來趨勢是什麼?Apr 25, 2025 am 12:12 AM

Java將通過雲原生應用、多平台部署和跨語言互操作進一步提昇平台獨立性。 1)雲原生應用將使用GraalVM和Quarkus提升啟動速度。 2)Java將擴展到嵌入式設備、移動設備和量子計算機。 3)通過GraalVM,Java將與Python、JavaScript等語言無縫集成,增強跨語言互操作性。

Java的強鍵入如何有助於平台獨立性?Java的強鍵入如何有助於平台獨立性?Apr 25, 2025 am 12:11 AM

Java的強類型系統通過類型安全、統一的類型轉換和多態性確保了平台獨立性。 1)類型安全在編譯時進行類型檢查,避免運行時錯誤;2)統一的類型轉換規則在所有平台上一致;3)多態性和接口機制使代碼在不同平台上行為一致。

說明Java本機界面(JNI)如何損害平台獨立性。說明Java本機界面(JNI)如何損害平台獨立性。Apr 25, 2025 am 12:07 AM

JNI會破壞Java的平台獨立性。 1)JNI需要特定平台的本地庫,2)本地代碼需在目標平台編譯和鏈接,3)不同版本的操作系統或JVM可能需要不同的本地庫版本,4)本地代碼可能引入安全漏洞或導致程序崩潰。

是否有任何威脅或增強Java平台獨立性的新興技術?是否有任何威脅或增強Java平台獨立性的新興技術?Apr 24, 2025 am 12:11 AM

新興技術對Java的平台獨立性既有威脅也有增強。 1)雲計算和容器化技術如Docker增強了Java的平台獨立性,但需要優化以適應不同雲環境。 2)WebAssembly通過GraalVM編譯Java代碼,擴展了其平台獨立性,但需與其他語言競爭性能。

JVM的實現是什麼,它們都提供了相同的平台獨立性?JVM的實現是什麼,它們都提供了相同的平台獨立性?Apr 24, 2025 am 12:10 AM

不同JVM實現都能提供平台獨立性,但表現略有不同。 1.OracleHotSpot和OpenJDKJVM在平台獨立性上表現相似,但OpenJDK可能需額外配置。 2.IBMJ9JVM在特定操作系統上表現優化。 3.GraalVM支持多語言,需額外配置。 4.AzulZingJVM需特定平台調整。

平台獨立性如何降低發展成本和時間?平台獨立性如何降低發展成本和時間?Apr 24, 2025 am 12:08 AM

平台獨立性通過在多種操作系統上運行同一套代碼,降低開發成本和縮短開發時間。具體表現為:1.減少開發時間,只需維護一套代碼;2.降低維護成本,統一測試流程;3.快速迭代和團隊協作,簡化部署過程。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

將Eclipse與SAP NetWeaver應用伺服器整合。

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具