Java集合知識總結


集合概述

集合:集合是Java中提供的一種容器,可以用來存儲多個數據。

 

 

集合和數組的區別:

(1)數組長度的是固定的,集合的長度是可變的。

(2)數組中存儲的都是同一類型的元素。集合存儲的都是對象,對象的類型可以不一致。

Java集合類主要由兩個根接口Collection和Map派生出來的。Collection有三個子接口: List、Set、Queue(Java5新增的隊列)。Java集合大致也可分成List、Set、Queue、Map四種接口體系,注意:Map不是Collection的子接口。

Map接口:雙列數據,保存具有映射關系“key-value對”

Collection接口

Collection接口:單列數據,定義了存取一組對象的方法的集合。

Collection接口是List、Set和Queue接口的父接口,該接口里定義的方法既可用於操作Set集合,也可用於操作List和 Queue集合。

Collection接口的常用方法

Collection子接口之一:List接口

List集合類中元素有序、且可重復,集合中的每個元素都有其對應的順序索引。List集合默認按照元素的添加順序設置元素的索引,可以通過索引(類似數組的下標)來訪問指定位置的集合元素。

List接口的實現類主要有:ArrayListLinkedListVector

List接口的常用方法

返回值類型 方法名及描述
boolean add(E e) 將指定的元素追加到此列表的末尾(可選操作)。
void add(int index, E element) 將指定的元素插入此列表中的指定位置(可選操作)。
boolean addAll(Collection c) 按指定集合的迭代器(可選操作)返回的順序將指定集合中的所有元素附加到此列表的末尾。
boolean addAll(int index, Collection c) 將指定集合中的所有元素插入到此列表中的指定位置(可選操作)。
void clear() 從此列表中刪除所有元素(可選操作)。
boolean contains(Object o) 如果此列表包含指定的元素,則返回true。
E get(int index) 返回此列表中指定位置的元素。
int hashCode() 返回此列表的哈希碼值。
int indexOf(Object o) 返回此列表中指定元素的第一次出現的索引,如果此列表不包含元素,則返回-1。
boolean isEmpty() 如果此列表不包含元素,則返回 true 。
Iterator iterator() 以正確的順序返回該列表中的元素的迭代器。
int lastIndexOf(Object o) 返回此列表中指定元素的最后一次出現的索引,如果此列表不包含元素,則返回-1。
E remove(int index) 刪除該列表中指定位置的元素(可選操作)。
E set(int index, E element) 用指定的元素(可選操作)替換此列表中指定位置的元素。
int size() 返回此列表中的元素數。

 

(1)List接口的實現類之一:ArrayList

ArrayList是List接口的主要實現類,ArrayList是一個動態數組,允許任何符合規則的元素插入包括null。 它能快速隨機訪問存儲的元素,支持隨機訪問, 查詢速度快, 增刪元素慢。

ArrayList的JDK1.8之前與之后的實現區別:

JDK1.7:直接創建一個初始容量為10的數組

JDK1.8:一開始先創建一個長度為0的數組,當添加第一個元素時再創建一個初始容量為10的數組

(2)List接口的實現類之二:LinkedList

LinkedList是List接口的另一個實現,除了可以根據索引訪問集合元素外,LinkedList還實現了Deque接口。

LinkedList內部以鏈表的形式保存集合中的元素,所以隨機訪問集合中的元素性能較差,但在頻繁的插入或刪除元素時有較好的性能。

(3)List接口的實現類之三:Vector

Vector大多數操作與ArrayList相同,區別之處在於Vector是線程安全的。

 面試題:

ArrayList和LinkedList的區別

都是線程不安全,相對線程安全的Vector,執行效率高。此外,ArrayList是實現了基於動態數組的數據結構,LinkedList基於鏈表的數據結構。對於隨機訪問get和set,ArrayList覺得優於LinkedList,因為LinkedList要移動指針。對於新增和刪除操作add(特指插入)和remove,LinkedList比較占優勢,因為ArrayList要移動數據。

ArrayList和Vector的區別

Vector和ArrayList幾乎是完全相同的,唯一的區別在於Vector是同步類(synchronized),屬於強同步類。因此開銷就比ArrayList要大,訪問要慢。大多數清空下使用 ArrayList而不是Vector,因為同步完全可以由自己來控制。Vector每次擴容請求其大小的2倍空間,而ArrayList是1.5倍。Vector還有一個子類Stack。

Collection子接口之二:Set接口

Set接口也是Collection的子接口,set接口沒有提供額外的方法。

Set集合不允許包含相同的元素,如果試把兩個相同的元素加入同一個Set集合中,則會添加操作失敗。

Set集合判斷兩個對象是否相同是根據 equals() 方法,而不是使用 == 運算符。

(1)Set接口的實現類之一:HashSet

HashSet是Set接口的典型實現,大多數時候使用Set集合時都使用這個實現類。

HashSet按Hash算法來存儲集合中的元素,因此具有很好的存取、查找、刪除性能。

HashSet 具有以下特點:

  • 不能保證元素的排列順序

  • HashSet不是線程安全的

  • 集合元素可以是null

HashSet集合判斷兩個元素相等的標准:兩個對象通過 hashCode() 方法比較相等,並且兩個對象的 equals() 方法返回值也相等。

對於存放在Set容器中的對象,對應的類一定要重寫equals()和hashCode(Object obj)方法,以實現對象相等規則。

HashSet添加元素的原理如下:

當向HashSet集合中存入一個元素時,HashSet會調用該對象的hashCode()方法來得到該對象的hashCode值,然后根據 hashCode值,通過某種散列函數決定該對象在HashSet底層數組中的存儲位置。

如果兩個元素的hashCode()值相等,會再繼續調用equals方法,如果equals方法結果為true,則添加失敗。如果為false,那么會保存該元素,但是該數組的位置已經有元素了, 那么會通過鏈表的方式繼續鏈接存儲。

如果兩個元素的equals() 方法返回true,但它們的 hashCode() 返回值不相等,hashSet將會把它們存儲在不同的位置,但依然可以添加成功。

重寫hashCode() 方法的基本原則

在程序運行時,同一個對象多次調用 hashCode() 方法應該返回相同的值

當兩個對象通過equals()方法比較返回true時,這兩個對象的hashCode()方法的返回值應該相等。

對象中用作equals()方法比較的實例變量,都應該用來計算hashCode值。

(2)Set接口的實現類之二:LinkedHashSet

LinkedHashSet是HashSet的子類。

LinkedHashSet也是根據元素的hashCode值來決定元素的存儲位置。但它同時使用雙向鏈表維護元素的次序,元素的順序與添加順序一致。

由於LinkedHashSet需要維護元素的插入順序,因此性能略低於HashSet,但在迭代訪問Set里的全部元素時有很好的性能。

LinkedHashSet不允許集合元素重復。

(3)Set接口的實現類之三:TreeSet

TreeSet是SortedSet接口的實現類,TreeSet可以確保集合元素處於排序狀態。

TreeSet底層使用紅黑樹結構存儲數據元素。

TreeSet兩種排序方法:自然排序和定制排序。默認情況下,TreeSet采用自然排序。

自然排序:

TreeSet會調用集合元素的compareTo(Object obj) 方法來比較元素之間的大小關系,然后將集合元素按升序(默認情況)排列。

如果試圖把一個對象添加到TreeSet時,則該對象的類必須實現Comparable接口。

實現Comparable的類必須實現compareTo(Object obj) 方法,兩個對象即通過compareTo(Object obj) 方法的返回值來比 較大小。

Comparable的一些典型實現類:

  • BigDecimal、BigInteger 以及所有的數值型對應的包裝類:按它們對應的數值大小進行比較

  • Character:按字符的 unicode值來進行比較

  • Boolean:true 對應的包裝類實例大於 false 對應的包裝類實例

  • String:按字符串中字符的 unicode 值進行比較

  • Date、Time:后邊的時間、日期比前面的時間、日期大

因為只有相同類的兩個實例才會比較大小,所以向TreeSet中添加的應該是同一個類的對象。

對於TreeSet 集合而言,它判斷兩個對象是否相等的唯一標准是:兩個對象通過compareTo(Object obj) 方法比較返回值。

當需要把一個對象放入TreeSet 中,重寫該對象對應的equals() 方法時,應保證該方法與compareTo(Object obj) 方法有一致的結果。

對於TreeSet集合而言,它判斷兩個對象是否相等的標准是:兩個對象通過compareTo(Object obj)方法比較是否返回0,如果返回0則相等。

定制排序

TreeSet的自然排序要求元素所屬的類實現Comparable接口,如果元素所屬的類沒有實現Comparable接口,或不希望按照升序(默認情況)的方式排列元素,希望按照其它屬性大小進行排序,則考慮使用定制排序。定制排序,通過Comparator接口來實現。需要重寫compare(T o1,T o2)方法。

利用int compare(T o1,T o2)方法,比較o1和o2的大小:如果方法返回正整數,則表示o1大於o2。

要實現定制排序,需要將實現Comparator接口的實例作為形參傳遞給TreeSet的構造器。

使用定制排序判斷兩個元素相等的標准是:通過Comparator比較兩個元素返回了0。

Map接口

Map與Collection並列存在。用於保存具有映射關系的數據:key-value

Map中的key和value都可以是任何引用類型的數據

Map中的key用Set來存放,不允許重復,即同一個Map對象所對應的類,須重寫hashCode()和equals()方法

Map接口的常用實現類:HashMap、TreeMap、LinkedHashMap和Properties

(1)Map接口的實現類之一:HashMap

HashMap是Map接口使用頻率最高的實現類。允許使用null鍵和null值,與HashSet一樣,不保證映射的順序。

所有的key構成的集合是Set:無序的、不可重復的。所以,key所在的類要重寫:equals()和hashCode()

所有的value構成的集合是Collection:無序的、可以重復的。所以,value所在的類要重寫:equals()

HashMap判斷兩個key相等的標准是:兩個key通過equals() 方法返回true, hashCode值也相等。

HashMap判斷兩個value相等的標准是:兩個value通過equals()方法返回true。

HashMap可以使用null值為key或value

HashMap源碼中的重要常量

DEFAULT_INITIAL_CAPACITY: HashMap的默認容量,16

MAXIMUM_CAPACITY: HashMap的最大支持容量,2^30

TREEIFY_THRESHOLD:Bucket中鏈表長度大於該默認值,轉化為紅黑樹。

UNTREEIFY_THRESHOLD:Bucket中紅黑樹存儲的Node小於該默認值,轉化為鏈表

table:存儲元素的數組,總是2的n次冪

entrySet:存儲具體元素的集

size:HashMap中存儲的鍵值對的數量

modCount:HashMap擴容和結構改變的次數。

HashMap的存儲結構

JDK8之前版本:

JDK8之前HashMap的存儲結構是數組+鏈表結構(即為鏈地址法) ,當實例化一個HashMap時,系統會創建一個長度為Capacity的Entry數組,這個長度在哈希表中被稱為容量 (Capacity),在這個數組中可以存放元素的位置我們稱之“桶”(bucket),每個bucket都有自己的索引,系統可以根據索引快速的查找bucket中的元素。

每個bucket中存儲一個元素,即一個Entry對象,但每一個Entry對象可以帶一個引用變量,用於指向下一個元素,因此,在一個桶中,就有可能生成一個Entry鏈。 而且新添加的元素作為鏈表的head。

JDK8之后版本:

JDK8之后HashMap的存儲結構是數組+鏈表+紅黑樹實現。當實例化一個HashMap時,會初始化initialCapacity和loadFactor,在put第一對映射關系時,系統會創建一個長度為initialCapacity的Node數組,這個長度在哈希表中被稱為容量(Capacity),在這個數組中可以存放元素的位置我們稱之為 “桶”(bucket),每個bucket都有自己的索引,系統可以根據索引快速的查找bucket中的元素。

每個bucket中存儲一個元素,即一個Node對象,但每一個Node對象可以帶一個引用變量next,用於指向下一個元素,因此,在一個桶中,就有可能生成一個Node鏈。也可能是一個一個TreeNode對象,每一個TreeNode對象可以有兩個葉子結點left和right,因此,在一個桶中,就有可能生成一個TreeNode樹。而新添加的元素作為鏈表的last,或樹的葉子結點。

(2)Map接口的實現類之二:LinkedHashMap

LinkedHashMap 是 HashMap的子類,在HashMap存儲結構的基礎上,使用了一對雙向鏈表來記錄添加元素的順序。 該鏈表負責維護Map的迭代順序,與插入順序一致,因此性能比HashMap低,但在迭代訪問Map里的全部元素時有較好的性能。

(3)Map接口的實現類之三:TreeMap

TreeMap存儲Key-Value對時,需要根據key-value對進行排序。TreeMap可以保證所有的Key-Value對處於有序狀態。底層采用紅黑樹的數據結構。

TreeMap也有兩種排序方式,自然排序和定制排序。

(4)Map接口的實現類之四:Hashtable

HashMap線程不安全,Hashtable是線程安全的。

HashMap可以使用null值為key或value,Hashtable不允許使用null作為key和value。

Hashtable實現原理和HashMap相同,底層都使用哈希表結構,查詢速度快。

Hashtable和HashMap一樣也不能保證其中Key-Value對的順序。

(5)Map接口的實現類之五:Properties

Properties類是Hashtable 的子類,該對象用於處理屬性文件。

由於屬性文件里的key、value都是字符串類型,所以Properties里的key和value都是字符串類型 。

Collections工具類

Collections是一個操作 Set、List 和 Map 等集合的工具類。

Collections 中提供了一系列靜態的方法對集合元素進行排序、查詢和修改等操作, 還提供了對集合對象設置不可變、對集合對象實現同步控制等方法。

Iterator迭代器接口

Iterator接口用來遍歷集合元素

Collection接口繼承了java.lang.Iterable接口,該接口有一個iterator()方法,所有實現了Collection接口的集合類都有一個iterator()方法,用以返回一個實現了 Iterator接口的對象。

集合對象每次調用iterator()方法都得到一個全新的迭代器對象。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM