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

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

生活随笔

當(dāng)前位置: 首頁(yè) >

java集合浅谈(一)

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

一、類庫(kù)結(jié)構(gòu)圖概覽

容器對(duì)象僅能持有對(duì)象引用(對(duì)象的指針),而不是Copy對(duì)象信息,從網(wǎng)上搜得幾張Java中集合類庫(kù)的結(jié)構(gòu)圖,如下所示:

?

二、解說(shuō)Collection

2.1 Collection

  (1)Collection是最基本的集合接口,由Collection接口派生的兩個(gè)接口是List和Set。JDK提供的類都繼承自Collection的“子接口”,如List和Set。

  (2)所有實(shí)現(xiàn)Collection接口的類都必須提供兩個(gè)標(biāo)準(zhǔn)的構(gòu)造函數(shù):無(wú)參數(shù)的構(gòu)造函數(shù)和有一個(gè)Collection參數(shù)的構(gòu)造函數(shù)。前者用于創(chuàng)建一個(gè)空的Collection,后者用于創(chuàng)建一個(gè)新的Collection,允許用戶復(fù)制一個(gè)Collection。

  (3)不論Collection的實(shí)際類型如何,它都支持一個(gè)iterator()的方法,該方法返回一個(gè)迭代子,可逐一訪問(wèn)Collection中每一個(gè)元素。用法如下:

Iterator it = collection.iterator(); // 獲得一個(gè)迭代子 while(it.hasNext()) {Object obj = it.next(); // 得到下一個(gè)元素 }

?

2.2 Collection和Map區(qū)別:

(1)Collection類型,每個(gè)位置只有一個(gè)元素。

(2)Map類型,持有key-value形式的數(shù)據(jù)(鍵值對(duì)),即其元素是成對(duì)的對(duì)象。

?

三、細(xì)說(shuō)List、Set、Map

3.1 List:以某種插入順序來(lái)維護(hù)元素順序,另外元素可以重復(fù)。

    ArrayList:是用數(shù)組來(lái)實(shí)現(xiàn)的,讀取速度快,插入與刪除速度慢(因?yàn)椴迦肱c刪除時(shí)要移動(dòng)后面的元素),適合于隨機(jī)訪問(wèn)。ArrayList初始化時(shí)不可指定容量,如果以new ArrayList()方式創(chuàng)建時(shí),初始容量為10個(gè);如果以new ArrayList(Collection c)初始化時(shí),容量為c.size()*1.1,即增加10%的容量。當(dāng)向ArrayList中添加一個(gè)元素時(shí),先進(jìn)行容器的容量調(diào)整,如果容量不夠時(shí),則增加至原來(lái)的1.5倍加1,再然后把元素加入到容器中,即以原始容量的0.5倍比率增加。

    LinkedList:是用雙向鏈表來(lái)實(shí)現(xiàn)的,刪除與插入速度快,讀取速度較慢,因?yàn)樗x取時(shí)是從頭向尾或從尾向頭查找元素,適合于元素的插入與刪除操作。

    Vector:功能與ArrayList幾乎相同,也是用數(shù)組來(lái)實(shí)現(xiàn)的,其添加、刪除等都是基于線程同步的。當(dāng)一個(gè)Iterator正在被使用,如果另一個(gè)線程改變了Vector的狀態(tài),這時(shí)將拋出ConcurrentModificationException異常,因此必須捕獲該異常。Vector初始化時(shí)可以設(shè)定容量,如果以new Vector()方式創(chuàng)建,則其初始容量為10,超過(guò)容量時(shí)以2倍容量增加;如果以new Vector(Collection c)方式創(chuàng)建,則其初始容量為c.size()*1.1,超過(guò)時(shí)以2倍容量增加;如果以new Vector(int initialCapacity, int capacityIncrement),則以capacityIncrement容量單位增加。

    Stack:Stack繼承自Vector,實(shí)現(xiàn)一個(gè)后進(jìn)先出的堆棧,線程同步。

?

3.2 Set:Set接口不保證維護(hù)元素的次序,隨機(jī)訪問(wèn)不具有意義(List或數(shù)組具備隨機(jī)訪問(wèn)性質(zhì)),存入Set的每個(gè)元素必須是唯一的(即元素不可重復(fù)),也就是說(shuō)加入Set的Object必須定義equals()方法以確保對(duì)象的唯一性。

    HashSet:HashSet是最常用的,其查詢速度最快(采用散列函數(shù)),存入HashSet的對(duì)象必須定義hashCode()方法,因?yàn)槠鋬?nèi)部以HashMap來(lái)實(shí)現(xiàn),?它不保證集合的迭代順序,特別是它不保證該順序恒久不變。此類允許使用?null元素,其實(shí)現(xiàn)不是同步的。

    LinkedHashSet:繼承了HashSet,其內(nèi)部使用LinkedHashMap實(shí)現(xiàn)(使用鏈表維護(hù)元素的順序(哈希函數(shù)+鏈表)),在使用迭代器遍歷LinkedHashSet時(shí),結(jié)果會(huì)按元素插入的次序顯示。

    TreeSet:TreeSet實(shí)現(xiàn)了SortedSet接口,其內(nèi)部以TreeMap來(lái)實(shí)現(xiàn),生成一個(gè)總是處于排序狀態(tài)的Set。

?

3.3 Map:Map提供的不是對(duì)象與數(shù)組的關(guān)聯(lián),而是對(duì)象和對(duì)象的關(guān)聯(lián)。

    TreeMap:鍵以某種排序規(guī)則排序,其內(nèi)部以red-black(紅-黑)樹數(shù)據(jù)結(jié)構(gòu)來(lái)實(shí)現(xiàn),實(shí)現(xiàn)了SortedMap接口

    HashMap:?HashMap是以哈希表數(shù)據(jù)結(jié)構(gòu)來(lái)實(shí)現(xiàn)的,查找對(duì)象時(shí)通過(guò)哈希函數(shù)計(jì)算其位置,它是為快速查詢而設(shè)計(jì)的,其內(nèi)部定義了一個(gè)hash表數(shù)組(Entry[] table),元素會(huì)通過(guò)哈希轉(zhuǎn)換函數(shù)將元素的哈希地址轉(zhuǎn)換成數(shù)組中存放的索引,如果有沖突,則使用散列鏈表的形式將所有相同哈希地址的元素串起來(lái)。

    LinkedHashMap:繼承HashMap,其內(nèi)部實(shí)體LinkedHashMap.Entry繼承自HashMap.Entry,LinkedHashMap.Entry在HashMap.Entry的基礎(chǔ)上新增了兩個(gè)實(shí)體引用(Entry before, after),這樣實(shí)體可以相互串鏈起來(lái)形成鏈,并且在LinkedHashMap中定義了一個(gè)頭節(jié)點(diǎn)(Entry header)用來(lái)指向循環(huán)雙向鏈的第一個(gè)元素(通過(guò)after指向)與最后一個(gè)元素(通過(guò)before指向)。在添加一個(gè)元素時(shí),先通過(guò)父類HashMap將元素加入到hash表數(shù)組里,然后再在鏈尾(header.before指向位置)添加(當(dāng)然這一過(guò)程只是調(diào)整LinkedHashMap.Entry對(duì)象內(nèi)部的before、after而已,并不是創(chuàng)建一個(gè)新的鏈表結(jié)構(gòu)向里加);刪除一個(gè)元素時(shí),先從hash表數(shù)組中刪除,再將被刪除的元素徹底的從雙向鏈中斷開,其實(shí)在鏈中添加與刪除操作與LinkedList是一樣的。

    WeakHashMap:WeakHashMap是一種改進(jìn)的HashMap,若一個(gè)key不再被外部所引用,那么該key可以被GC回收。

    Hashtable:Hashtable是以哈希表數(shù)據(jù)結(jié)構(gòu)來(lái)實(shí)現(xiàn)的,解決沖突時(shí)與HashMap一樣,也是采用了散列鏈表的形式,不過(guò)性能比HashMap要低。

?

3.4 集合中的鍵值是否允許為null

(1)List:可以有多個(gè)null。

(2)HashSet:能插入一個(gè)null(其內(nèi)部以HashMap實(shí)現(xiàn)?),忽略重復(fù)元素(即不插入重復(fù)元素)。

(3)TreeSet:不能插入null?(其內(nèi)部以TreeMap?實(shí)現(xiàn)?)?,且元素不能重復(fù),如果待插入的元素已經(jīng)存在,則不插入。

(4)HashMap:允許一個(gè)null鍵與多個(gè)null值;若鍵重復(fù),則覆蓋以前值。

(5)HashTable:不允許null鍵與null值(否則運(yùn)行進(jìn)報(bào)空指針異常);若鍵重復(fù),則覆蓋以前值。

?(6)TreeMap:不允許null鍵(實(shí)際上可以插入一個(gè)null鍵,如果這個(gè)Map里只有一個(gè)元素是不會(huì)報(bào)錯(cuò)的,因?yàn)橐粋€(gè)元素時(shí)沒有排序操作,也就不會(huì)報(bào)空指針異常,但如果插入第二個(gè)時(shí)就會(huì)立即報(bào)錯(cuò)),但允許多個(gè)null值;若鍵重復(fù),則覆蓋以前值。

?

此處看一個(gè)HashMap的簡(jiǎn)單示例:若鍵重復(fù),則覆蓋以前值

package com.test;import java.util.*;public class Test {public static void main(String[] args) {Map map = new HashMap();map.put("Rajib Sarma", "100");map.put("Rajib Sarma", "200");// The value "100" is replaced by "200".map.put("Sazid Ahmed", "200");Iterator iter = map.entrySet().iterator();while (iter.hasNext()) {Map.Entry entry = (Map.Entry) iter.next();Object key = entry.getKey();Object val = entry.getValue();System.out.println(key);System.out.println(val);}} }

結(jié)果如下:

Sazid Ahmed 200 Rajib Sarma 200

?

四、應(yīng)用場(chǎng)景

4.1 對(duì)List的選擇

(1)對(duì)于隨機(jī)查詢與迭代遍歷操作,數(shù)組比所有的容器都要快。

(2)從中間的位置插入和刪除元素,LinkedList要比ArrayList快,特別是刪除操作。

(3)Vector通常不如ArrayList快,且應(yīng)該避免使用,它目前仍然存在于類庫(kù)中的原因是為了支持過(guò)去的代碼。

(4)最佳實(shí)踐:將ArrayList作為默認(rèn)首選,只有當(dāng)程序的性能因經(jīng)常從list中間進(jìn)行插入和刪除而變差的時(shí)候才去選擇LinkedList。當(dāng)然了,如果只是使用固定數(shù)量的元素,就應(yīng)該選擇數(shù)組了。

?

4.2 對(duì)Set的選擇

(1)HashSet的性能總比TreeSet好(特別是最常用的添加和查找元素操作)。

(2)TreeSet存在的唯一原因是,它可以維持元素的排序狀態(tài),所以只有當(dāng)你需要一個(gè)排好序的Set時(shí),才應(yīng)該使用TreeSet。

(3)對(duì)于插入操作,LinkedHashSet比HashSet略微慢一點(diǎn):這是由于維護(hù)鏈表所帶來(lái)額外開銷造成的。不過(guò),因?yàn)橛辛随湵?#xff0c;遍歷LinkedHashSet會(huì)比HashSet更快。

?

4.3 對(duì)Map的選擇

(1)HashMap和Hashtable的效率大致相同(通常HashMap更快一點(diǎn),所以HashMap有意取代Hashtable)。

(2)TreeMap通常比HashMap慢,因?yàn)橐S護(hù)排序。

(3)HashMap正是為快速查詢而設(shè)計(jì)的。

(4)LinkedHashMap比HashMap慢一點(diǎn),因?yàn)樗S護(hù)散列數(shù)據(jù)結(jié)構(gòu)的同時(shí)還要維護(hù)鏈表。

?

五、Iterator

http://blog.csdn.net/chenssy/article/details/37521461

5.1 Iterator對(duì)ArrayList(LinkedList)的操作限制

(1)剛實(shí)例化的迭代器如果還沒有進(jìn)行后移操作(next)是不能馬上進(jìn)行刪除與修改操作的。

(2)進(jìn)行添加操作后是不能立即進(jìn)行刪除與修改操作的。

(3)進(jìn)行刪除操作后可以進(jìn)行添加,但不能進(jìn)行修改操作。

(4)進(jìn)行修改后是可以立即進(jìn)行刪除與添加操作的。

(5)可以用ListIterator對(duì)集合連續(xù)添加與修改,但不能連續(xù)刪除。

?

5.2 通過(guò)迭代器修改集合結(jié)構(gòu)

在使用迭代器遍歷集合時(shí),我們不能通過(guò)集合本身來(lái)修改集合的結(jié)構(gòu)(添加、刪除),只能通過(guò)迭代器來(lái)操作。

下面是對(duì)HashMap進(jìn)行刪除操作的測(cè)試,其它集合也是這樣:

package com.test;import java.util.*; import java.util.Map.Entry;public class Test {public static void main(String[] args) {Map map = new HashMap();map.put(1, 1);map.put(2, 3);Set entrySet = map.entrySet();Iterator it = entrySet.iterator();while (it.hasNext()) {Entry entry = (Entry) it.next();/** 可以通過(guò)迭代器來(lái)修改集合結(jié)構(gòu),但前提是要在已執(zhí)行過(guò)next或前移操作,* 否則會(huì)拋異常:IllegalStateException*///it.remove();/** 拋異常:ConcurrentModificationException* 不能使用集合本身來(lái)修改集合的結(jié)構(gòu)*/// map.remove(entry.getKey());}//end while System.out.println(map);} }

?

六、HashMap

6.1 HashMap的數(shù)據(jù)結(jié)構(gòu)

HashMap是一個(gè)數(shù)組和鏈表的結(jié)合體(在數(shù)據(jù)結(jié)構(gòu)稱“鏈表散列“),如下圖所示:

  當(dāng)我們往HashMap中put元素的時(shí)候,先根據(jù)key的hash值得到這個(gè)元素在數(shù)組中的位置(即下標(biāo)),然后就可以把這個(gè)元素放到對(duì)應(yīng)的位置中了。如果這個(gè)元素所在的位置上已經(jīng)存放有其他元素,那么在同一個(gè)位置上的元素將以鏈表的形式存放,新加入的元素放在鏈頭,之前的元素放在鏈尾,如下圖所示:

注意:與TreeMap不同,HashMap不保證元素順序,根據(jù)需要該容器可能會(huì)對(duì)元素重新哈希,元素的順序會(huì)被打散,因此不同時(shí)間迭代同一個(gè)HashMap的順序可能會(huì)不同。

?

?

6.2 HashMap和Hashtable的區(qū)別

(1)在HashMap中,可以允許null作為鍵,且只可以有一個(gè),否則覆蓋,但可以有一個(gè)或多個(gè)值為null。當(dāng)get()方法返回null時(shí),既可以表示 HashMap中沒有該鍵,也可以表示該鍵所對(duì)應(yīng)的值為null,所以HashMap不能由get()方法來(lái)判斷是否存在某個(gè)鍵,而應(yīng)該用containsKey()方法來(lái)判斷;而Hashtable不允許null鍵與null值。

(2)HashMap中hash數(shù)組的默認(rèn)大小是16,而且一定是2的多少次方;HashTable中hash數(shù)組的默認(rèn)大小是11,增加的方式是 int newCapacity = oldCapacity * 2 + 1;,即增加至2倍(而不是2倍加1,因?yàn)閿U(kuò)容是在增加元素前進(jìn)行的,在擴(kuò)容后會(huì)將新增元素放入容器中)。另外兩者的默認(rèn)負(fù)載因子都是0.75。

(3)HashMap是Map接口的一個(gè)實(shí)現(xiàn)類;Hashtable是Dictionary的子類

public class HashMap extends AbstractMap implements Map public class Hashtable extends Dictionary implements Map

(4)HashMap中的方法在缺省情況下是非同步的,而Hashtable中的方法是同步的。在多線程應(yīng)用程序中,我們應(yīng)該使用Hashtable;而對(duì)于HashMap,則需要額外的同步機(jī)制(其實(shí)HashMap的同步問(wèn)題可通過(guò)Collections的一個(gè)靜態(tài)方法得到解決:Map Collections.synchronizedMap(Map m),當(dāng)然也可以自己在使用地方加鎖)。

  注:java.util.concurrent.ConcurrentHashMap是HashMap的線程安全版,同HashMap相比,ConcurrentHashMap不僅保證了訪問(wèn)的線程安全性,而且在效率上與Hashtable相比,有較大的提高。

(5)兩者遍歷方式的內(nèi)部實(shí)現(xiàn)不同,HashMap、Hashtable均使用了Iterator,而由于歷史原因,Hashtable還使用了Enumeration的方式 。

(6)求哈希地址與哈希地址轉(zhuǎn)hash數(shù)組(Entry table[])索引的方法不同,如下所示:

HashTable直接使用對(duì)象的hashCode:

int hash = key.hashCode();//直接使用鍵的hashCode方法求哈希值 //哈希地址轉(zhuǎn)hash數(shù)組索引,先使用最大正int數(shù)與,這樣將負(fù)轉(zhuǎn)正數(shù),再與數(shù)組長(zhǎng)度求模得到存入的hash數(shù)組索引位置 int index = (hash & 0x7FFFFFFF) % tab.length;

HashMap重新計(jì)算hash值,而且用位運(yùn)算&代替求模:

int hash = hash(k); int i = indexFor(hash, table.length); static int hash(Object x) { //以鍵本身的hash碼為基礎(chǔ)求哈希地址,但看不懂是什么意思 int h = x.hashCode(); h += ~(h << 9); h ^= (h >>> 14); h += (h << 4); h ^= (h >>> 10); return h; }
static int indexFor(int h, int length) { return h & (length-1);//將哈希地址轉(zhuǎn)換成哈希數(shù)組中存入的索引號(hào) }

?

?

補(bǔ)充:

(1)當(dāng)以自己的對(duì)象做為HashMap、HashTable、LinkedHashMap、HashSet 、LinkedHashSet 的鍵時(shí),一定要重寫hashCode ()與equals ()方法,因?yàn)镺bject的hashCode()是返回內(nèi)存地址,且equals()方法也是比較內(nèi)存地址,所以當(dāng)要在這些hash集合中查找時(shí),如果是另外new出的新對(duì)象是查不到的,除非重寫這兩個(gè)方法。因?yàn)锳bstractMap類的containsKey(Object key)方法實(shí)現(xiàn)如下:

if (e.hash == hash && eq(k, e.key))//先比對(duì)hashcode,再使用equals return true; static boolean eq(Object x, Object y) { return x == y || x.equals(y); }

Java中的集合框架的哈希是以一個(gè)對(duì)象查找另外一個(gè)對(duì)象,所以重寫hasCode與equals方法很重要。String對(duì)象是可以作為鍵的,因?yàn)橐阎貙懥诉@兩個(gè)方法。

(2)重寫hashCode()與equals()這兩個(gè)方法是針對(duì)哈希類,至于其它集合,如果要用public boolean contains(Object o)或containsValue(Object value)查找時(shí),只需要實(shí)現(xiàn)equals()方法即可,他們都只使用對(duì)象的 equals方法進(jìn)行比對(duì),沒有使用 hashCode方法。

(3)TreeMap/TreeSet:放入其中的元素一定要具有自然比較能力(即要實(shí)現(xiàn)java.lang.Comparable接口)或者在構(gòu)造TreeMap/TreeSet時(shí)傳入一個(gè)比較器(實(shí)現(xiàn)java.util.Comparator接口),如果在創(chuàng)建時(shí)沒有傳入比較器,而放入的元素也沒有自然比較能力時(shí),會(huì)出現(xiàn)類型轉(zhuǎn)換錯(cuò)誤(因?yàn)樵跊]有較器時(shí),會(huì)試著轉(zhuǎn)成Comparable型)。

兩種比較接口如下:

//自然比較器 public interface java.lang.Comparable { public int compareTo(Object o); } public interface java.util.Comparator { int compare(Object o1, Object o2); boolean equals(Object obj); }

(4)在多線程環(huán)境下,可以使用Collections類的相應(yīng)靜態(tài)方法來(lái)包裝相應(yīng)的集合類,使它們線程安全:

A、public static Collection synchronizedCollection (Collection c)方法的實(shí)質(zhì)是返回包裝后的SynchronizedCollection子類。

B、使用Collections的synchronizedList、synchronizedMap、synchronizedSet等方法來(lái)獲取經(jīng)過(guò)包裝了的同步集合(如:List list = Collections.synchronizedList(new LinkedList(...));或?Collections.synchronizedMap(originMap)?)

?

Collections代碼如下:

public class Collections { //... static Collection synchronizedCollection(Collection c, Object mutex) { return new SynchronizedCollection(c, mutex); } public static List synchronizedList(List list) { //... } static Set synchronizedSet(Set s, Object mutex) { //... } public static Map synchronizedMap(Map m) { return new SynchronizedMap(m); } //... static class SynchronizedCollection implements Collection, Serializable { Collection c; // 對(duì)給定集合進(jìn)行同步(包裝) Object mutex; // 對(duì)象鎖,可以自己設(shè)置 //... SynchronizedCollection(Collection c, Object mutex) { this.c = c; this.mutex = mutex; } public int size() { synchronized (mutex) { return c.size(); } } public boolean isEmpty() { synchronized (mutex) { return c.isEmpty(); } } //... } static class SynchronizedList extends SynchronizedCollection implements List { List list; SynchronizedList(List list, Object mutex) { super(list, mutex); this.list = list; } public Object get(int index) { synchronized (mutex) { return list.get(index); } } //... } static class SynchronizedSet extends SynchronizedCollection implements Set { SynchronizedSet(Set s) { super(s); } //... } //... }

?

?

隊(duì)列類圖:

Deque(雙端隊(duì)列):兩端都可以進(jìn)出的隊(duì)列。當(dāng)我們約束從隊(duì)列的一端進(jìn)出時(shí),就形成了另一種存取模式,它遵循先進(jìn)后出原則,這就是棧結(jié)構(gòu)。

?

參考資料

(1)http://www.blogjava.net/EvanLiu/archive/2007/11/12/159884.html

(2)http://www.cnblogs.com/CarpenterLee/p/5440428.html

(3)http://www.cnblogs.com/caca/p/java_Hashtable.html

轉(zhuǎn)載于:https://www.cnblogs.com/studyLog-share/p/4691431.html

總結(jié)

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

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