一、集合框架圖
簡化圖:
說明:對于以上的框架圖有如下幾點說明
1.所有集合類都位于java.util包下。Java的集合類主要由兩個接口派生而出:Collection和Map,Collection和Map是Java集合框架的根接口,這兩個接口又包含了一些子接口或?qū)崿F(xiàn)類。
2. 集合接口:6個接口(短虛線表示),表示不同集合類型,是集合框架的基礎(chǔ)。
3. 抽象類:5個抽象類(長虛線表示),對集合接口的部分實現(xiàn)??蓴U展為自定義集合類。
4. 實現(xiàn)類:8個實現(xiàn)類(實線表示),對接口的具體實現(xiàn)。
5. Collection 接口是一組允許重復(fù)的對象。
6. Set 接口繼承 Collection,集合元素不重復(fù)。
7. List 接口繼承 Collection,允許重復(fù),維護元素插入順序。
8. Map接口是鍵-值對象,與Collection接口沒有什么關(guān)系。
9.Set、List和Map可以看做集合的三大類:
List集合是有序集合,集合中的元素可以重復(fù),訪問集合中的元素可以根據(jù)元素的索引來訪問。
Set集合是無序集合,集合中的元素不可以重復(fù),訪問集合中的元素只能根據(jù)元素本身來訪問(也是集合里元素不允許重復(fù)的原因)。
Map集合中保存Key-value對形式的元素,訪問時只能根據(jù)每項元素的key來訪問其value。
二、總體分析
大致說明:
看上面的框架圖,先抓住它的主干,即Collection和Map。
1、Collection是一個接口,是高度抽象出來的集合,它包含了集合的基本操作和屬性。Collection包含了List和Set兩大分支。
(1)List是一個有序的隊列,每一個元素都有它的索引。第一個元素的索引值是0。List的實現(xiàn)類有LinkedList, ArrayList, Vector, Stack。
(2)Set是一個不允許有重復(fù)元素的集合。Set的實現(xiàn)類有HastSet和TreeSet。HashSet依賴于HashMap,它實際上是通過HashMap實現(xiàn)的;TreeSet依賴于TreeMap,它實際上是通過TreeMap實現(xiàn)的。
2、Map是一個映射接口,即key-value鍵值對。Map中的每一個元素包含“一個key”和“key對應(yīng)的value”。AbstractMap是個抽象類,它實現(xiàn)了Map接口中的大部分API。而HashMap,TreeMap,WeakHashMap都是繼承于AbstractMap。Hashtable雖然繼承于Dictionary,但它實現(xiàn)了Map接口。
3、接下來,再看Iterator。它是遍歷集合的工具,即我們通常通過Iterator迭代器來遍歷集合。我們說Collection依賴于Iterator,是因為Collection的實現(xiàn)類都要實現(xiàn)iterator()函數(shù),返回一個Iterator對象。ListIterator是專門為遍歷List而存在的。
4、再看Enumeration,它是JDK 1.0引入的抽象類。作用和Iterator一樣,也是遍歷集合;但是Enumeration的功能要比Iterator少。在上面的框圖中,Enumeration只能在Hashtable, Vector, Stack中使用。
5、最后,看Arrays和Collections。它們是操作數(shù)組、集合的兩個工具類。
有了上面的整體框架之后,我們接下來對每個類分別進行分析。
三、Collection接口
Collection接口是處理對象集合的根接口,其中定義了很多對元素進行操作的方法。Collection接口有兩個主要的子接口List和Set,注意Map不是Collection的子接口,這個要牢記。
Collection接口中的方法如下:
其中,有幾個比較常用的方法,比如方法add()添加一個元素到集合中,addAll()將指定集合中的所有元素添加到集合中,contains()方法檢測集合中是否包含指定的元素,toArray()方法返回一個表示集合的數(shù)組。
另外,Collection中有一個iterator()函數(shù),它的作用是返回一個Iterator接口。通常,我們通過Iterator迭代器來遍歷集合。ListIterator是List接口所特有的,在List接口中,通過ListIterator()返回一個ListIterator對象。
Collection接口有兩個常用的子接口,下面詳細介紹。
1.List接口
List集合代表一個有序集合,集合中每個元素都有其對應(yīng)的順序索引。List集合允許使用重復(fù)元素,可以通過索引來訪問指定位置的集合元素。
List接口繼承于Collection接口,它可以定義一個允許重復(fù)的有序集合。因為List中的元素是有序的,所以我們可以通過使用索引(元素在List中的位置,類似于數(shù)組下標(biāo))來訪問List中的元素,這類似于Java的數(shù)組。
List接口為Collection直接接口。List所代表的是有序的Collection,即它用某種特定的插入順序來維護元素順序。用戶可以對列表中每個元素的插入位置進行精確地控制,同時可以根據(jù)元素的整數(shù)索引(在列表中的位置)訪問元素,并搜索列表中的元素。實現(xiàn)List接口的集合主要有:ArrayList、LinkedList、Vector、Stack。
(1)ArrayList
ArrayList是一個動態(tài)數(shù)組,也是我們最常用的集合。它允許任何符合規(guī)則的元素插入甚至包括null。每一個ArrayList都有一個初始容量(10),該容量代表了數(shù)組的大小。隨著容器中的元素不斷增加,容器的大小也會隨著增加。在每次向容器中增加元素的同時都會進行容量檢查,當(dāng)快溢出時,就會進行擴容操作。所以如果我們明確所插入元素的多少,最好指定一個初始容量值,避免過多的進行擴容操作而浪費時間、效率。
size、isEmpty、get、set、iterator 和 listIterator 操作都以固定時間運行。add 操作以分攤的固定時間運行,也就是說,添加 n 個元素需要 O(n) 時間(由于要考慮到擴容,所以這不只是添加元素會帶來分攤固定時間開銷那樣簡單)。
ArrayList擅長于隨機訪問。同時ArrayList是非同步的。
(2)LinkedList
同樣實現(xiàn)List接口的LinkedList與ArrayList不同,ArrayList是一個動態(tài)數(shù)組,而LinkedList是一個雙向鏈表。所以它除了有ArrayList的基本操作方法外還額外提供了get,remove,insert方法在LinkedList的首部或尾部。
由于實現(xiàn)的方式不同,LinkedList不能隨機訪問,它所有的操作都是要按照雙重鏈表的需要執(zhí)行。在列表中索引的操作將從開頭或結(jié)尾遍歷列表(從靠近指定索引的一端)。這樣做的好處就是可以通過較低的代價在List中進行插入和刪除操作。
與ArrayList一樣,LinkedList也是非同步的。如果多個線程同時訪問一個List,則必須自己實現(xiàn)訪問同步。一種解決方法是在創(chuàng)建List時構(gòu)造一個同步的List:
List list = Collections.synchronizedList(new LinkedList(...));
(3)Vector
與ArrayList相似,但是Vector是同步的。所以說Vector是線程安全的動態(tài)數(shù)組。它的操作與ArrayList幾乎一樣。
(4)Stack
Stack繼承自Vector,實現(xiàn)一個后進先出的堆棧。Stack提供5個額外的方法使得Vector得以被當(dāng)作堆棧使用?;镜膒ush和pop 方法,還有peek方法得到棧頂?shù)脑?,empty方法測試堆棧是否為空,search方法檢測一個元素在堆棧中的位置。Stack剛創(chuàng)建后是空棧。
2.Set接口
Set是一種不包括重復(fù)元素的Collection。它維持它自己的內(nèi)部排序,所以隨機訪問沒有任何意義。與List一樣,它同樣允許null的存在但是僅有一個。由于Set接口的特殊性,所有傳入Set集合中的元素都必須不同,同時要注意任何可變對象,如果在對集合中元素進行操作時,導(dǎo)致e1.equals(e2)==true,則必定會產(chǎn)生某些問題。Set接口有三個具體實現(xiàn)類,分別是散列集HashSet、鏈?zhǔn)缴⒘屑疞inkedHashSet和樹形集TreeSet。
Set是一種不包含重復(fù)的元素的Collection,無序,即任意的兩個元素e1和e2都有e1.equals(e2)=false,Set最多有一個null元素。需要注意的是:雖然Set中元素沒有順序,但是元素在set中的位置是由該元素的HashCode決定的,其具體位置其實是固定的。
此外需要說明一點,在set接口中的不重復(fù)是有特殊要求的。
舉一個例子:對象A和對象B,本來是不同的兩個對象,正常情況下它們是能夠放入到Set里面的,但是如果對象A和B的都重寫了hashcode和equals方法,并且重寫后的hashcode和equals方法是相同的話。那么A和B是不能同時放入到Set集合中去的,也就是Set集合中的去重和hashcode與equals方法直接相關(guān)。
為了更好地理解,請看下面的例子:
public class Test{
public static void main(String[] args) {
Set set=new HashSet();
set.add("Hello");
set.add("world");
set.add("Hello");
System.out.println("集合的尺寸為:"+set.size());
System.out.println("集合中的元素為:"+set.toString());
}
}
運行結(jié)果:
集合的尺寸為:2
集合中的元素為:[world, Hello]
分析:由于String類中重寫了hashcode和equals方法,用來比較指向的字符串對象所存儲的字符串是否相等。所以這里的第二個Hello是加不進去的。
再看一個例子:
public class TestSet {
public static void main(String[] args){
Set books = new HashSet();
//添加一個字符串對象
books.add(new String("Struts2權(quán)威指南"));
//再次添加一個字符串對象,
//因為兩個字符串對象通過equals方法比較相等,所以添加失敗,返回false
boolean result = books.add(new String("Struts2權(quán)威指南"));
System.out.println(result);
//下面輸出看到集合只有一個元素
System.out.println(books);
}
}
運行結(jié)果:
false
[Struts2權(quán)威指南]
說明:程序中,book集合兩次添加的字符串對象明顯不是一個對象(程序通過new關(guān)鍵字來創(chuàng)建字符串對象),當(dāng)使用==運算符判斷返回false,使用equals方法比較返回true,所以不能添加到Set集合中,最后只能輸出一個元素。
(1)HashSet
HashSet 是一個沒有重復(fù)元素的集合。它是由HashMap實現(xiàn)的,不保證元素的順序(這里所說的沒有順序是指:元素插入的順序與輸出的順序不一致),而且HashSet允許使用null 元素。HashSet是非同步的,如果多個線程同時訪問一個哈希set,而其中至少一個線程修改了該set,那么它必須保持外部同步。 HashSet按Hash算法來存儲集合的元素,因此具有很好的存取和查找性能。
HashSet的實現(xiàn)方式大致如下,通過一個HashMap存儲元素,元素是存放在HashMap的Key中,而Value統(tǒng)一使用一個Object對象。
HashSet使用和理解中容易出現(xiàn)的誤區(qū):
a.HashSet中存放null值
HashSet中是允許存入null值的,但是在HashSet中僅僅能夠存入一個null值。
b.HashSet中存儲元素的位置是固定的
HashSet中存儲的元素的是無序的,這個沒什么好說的,但是由于HashSet底層是基于Hash算法實現(xiàn)的,使用了hashcode,所以HashSet中相應(yīng)的元素的位置是固定的。
c.必須小心操作可變對象(Mutable Object)。如果一個Set中的可變元素改變了自身狀態(tài)導(dǎo)致Object.equals(Object)=true將導(dǎo)致一些問題。
(2)LinkedHashSet
LinkedHashSet繼承自HashSet,其底層是基于LinkedHashMap來實現(xiàn)的,有序,非同步。LinkedHashSet集合同樣是根據(jù)元素的hashCode值來決定元素的存儲位置,但是它同時使用鏈表維護元素的次序。這樣使得元素看起來像是以插入順序保存的,也就是說,當(dāng)遍歷該集合時候,LinkedHashSet將會以元素的添加順序訪問集合的元素。
(3)TreeSet
TreeSet是一個有序集合,其底層是基于TreeMap實現(xiàn)的,非線程安全。TreeSet可以確保集合元素處于排序狀態(tài)。TreeSet支持兩種排序方式,自然排序和定制排序,其中自然排序為默認的排序方式。當(dāng)我們構(gòu)造TreeSet時,若使用不帶參數(shù)的構(gòu)造函數(shù),則TreeSet的使用自然比較器;若用戶需要使用自定義的比較器,則需要使用帶比較器的參數(shù)。
注意:TreeSet集合不是通過hashcode和equals函數(shù)來比較元素的.它是通過compare或者comparaeTo函數(shù)來判斷元素是否相等.compare函數(shù)通過判斷兩個對象的id,相同的id判斷為重復(fù)元素,不會被加入到集合中。
由于個人時間問題今天的分享就先到這里,有興趣的同學(xué)可以關(guān)注我,留意下節(jié)文章的發(fā)布。
每天都在分享文章,也每天都有人想要我出來給大家分享下怎么去學(xué)習(xí)Java。大家都知道,我們是學(xué)Java全棧的,大家就肯定以為我有全套的Java系統(tǒng)教程。沒錯,我是有Java全套系統(tǒng)教程,進扣裙【47】974【9726】所示,今天小編就免費送!~
后記:對于大部分轉(zhuǎn)行的人來說,找機會把自己的基礎(chǔ)知識補齊,邊工作邊補基礎(chǔ)知識,真心很重要。
“我們相信人人都可以成為一個程序員,現(xiàn)在開始,找個師兄,帶你入門,學(xué)習(xí)的路上不再迷茫。這里是ja+va修真院,初學(xué)者轉(zhuǎn)行到互聯(lián)網(wǎng)行業(yè)的聚集地。"