集合-2(Set(HashSet、TreeSet、LinkedHashSet)、List(ArrayList、LinkedList、Vector)、Map(HashMap、TreeMap...))
1.Set接口
集合中的元素不能重復(fù),所以存入Set的元素都必須定義equals()來(lái)確保對(duì)象的唯一性。
無(wú)序、無(wú)索引
1.1HashSet類(lèi)
實(shí)現(xiàn)了Set接口,此實(shí)現(xiàn)不是同步的。
由哈希表支持。實(shí)際上是一個(gè)HashMap集合。
不能保證迭代順序和存儲(chǔ)順序一致。特別是它不保證該順序恒久不變。
保證元素唯一的方式:hashCode()和equals()(若為自定義類(lèi),需重寫(xiě)兩個(gè)方法)。
假定哈希函數(shù)將這些元素正確地分布在桶中。對(duì)此 set 進(jìn)行迭代所需的時(shí)間與 HashSet 實(shí)例的大小(元素的數(shù)量)和底層 HashMap 實(shí)例(桶的數(shù)量)的“容量”的和成比例。因此,如果迭代性能很重要,則不要將初始容量設(shè)置得太高(或?qū)⒓虞d因子設(shè)置得太低)。
1.1.1哈希表
底層使用數(shù)組機(jī)制。
數(shù)組中存放對(duì)象
由對(duì)象的特有數(shù)據(jù)結(jié)合相應(yīng)的算法(Object中為hashCode()),計(jì)算出此對(duì)象在數(shù)組中的位置。
哈希沖突
2個(gè)對(duì)象計(jì)算出的hashCode()結(jié)果一樣。
則調(diào)用此對(duì)象的equals(),判斷兩個(gè)對(duì)象是否一樣。
- 一樣,不存第二個(gè),
- 不一樣,存
1.2TreeSet
使用元素的自然順序?qū)υ剡M(jìn)行排序,或者根據(jù)創(chuàng)建 set 時(shí)提供的 Comparator 進(jìn)行排序,具體取決于使用的構(gòu)造方法。
此實(shí)現(xiàn)為基本操作(add、remove 和 contains)提供受保證的 log(n) 時(shí)間開(kāi)銷(xiāo)。
此實(shí)現(xiàn)不是同步的。
1.2.1構(gòu)造方法
TreeSet(Collection<T> coll):構(gòu)造一個(gè)包含指定 collection 元素的新 TreeSet,它按照其元素的自然順序進(jìn)行排序。
1.2.1方法
E ? last():?返回此 set 中當(dāng)前最后一個(gè)(最高)元素。
E? first():返回此 set 中當(dāng)前第一個(gè)(最低)元素。
1.3LinkedHashSet
HashSet的子類(lèi)。
數(shù)據(jù)存儲(chǔ)結(jié)構(gòu):鏈表+哈希表
保證元素的存取和取出順序一致。
2.List接口
有序的 collection(也稱(chēng)為序列)。
此接口的用戶(hù)可以對(duì)列表中每個(gè)元素的插入位置進(jìn)行精確地控制。
用戶(hù)可以根據(jù)元素的整數(shù)索引(在列表中的位置)訪問(wèn)元素,并搜索列表中的元素。
通常允許重復(fù)的元素。列表通常允許滿(mǎn)足 e1.equals(e2) 的元素對(duì) e1 和 e2,并且如果列表本身允許 null 元素的話,通常它們允許多個(gè) null 元素。
ListIterator listIterator() :返回此列表元素的列表迭代器(按適當(dāng)順序)。
2.1 ArrayList
List 接口的大小可變數(shù)組的實(shí)現(xiàn).
此類(lèi)大致上等同于 Vector 類(lèi),除了此類(lèi)是不同步的。
每個(gè) ArrayList 實(shí)例都有一個(gè)容量。該容量是指用來(lái)存儲(chǔ)列表元素的數(shù)組的大小。它總是至少等于列表的大小。隨著向 ArrayList 中不斷添加元素,其容量也自動(dòng)增長(zhǎng)。并未指定增長(zhǎng)策略的細(xì)節(jié)。
在添加大量元素前,應(yīng)用程序可以使用 ensureCapacity 操作來(lái)增加 ArrayList 實(shí)例的容量。這可以減少遞增式再分配的數(shù)量。
2.1.1構(gòu)造方法
ArrayList():構(gòu)造一個(gè)初始容量為 10 的空列表。
ArrayList(Collection<E> coll):?構(gòu)造一個(gè)包含指定 collection 的元素的列表,這些元素是按照該 collection 的迭代器返回它們的順序排列的。
ArrayList(int initialCapacity);構(gòu)造一個(gè)具有指定初始容量的空列表。
2.1.2常用方法
boolean add(E e):將指定的元素添加到此列表的尾部
void add(int index,E e):將指定的元素插入此列表中的指定位置。原位置元素后移。
boolean add(int index,Collection<E> coll):從指定的位置開(kāi)始,將指定 collection 中的所有元素插入到此列表中。
E remove(int index):移除此列表中指定位置上的元素。并返回被刪除的元素。
E set(int index,E e):用指定的元素替代此列表中指定位置上的元素。返回此位置上的原元素。
- ArrayList的contains()方法源碼:
2.2LinkedList
List 接口的鏈接列表實(shí)現(xiàn)。
采用雙向列表實(shí)現(xiàn)的,對(duì)數(shù)據(jù)的索引需要從列表頭開(kāi)始遍歷,隨機(jī)訪問(wèn)效率低;插入元素時(shí)不需要對(duì)數(shù)據(jù)進(jìn)行移動(dòng),所以插入效率高。LinkedList是非線程安全的容器。
此類(lèi)實(shí)現(xiàn) Deque 接口,為 add、poll 提供先進(jìn)先出隊(duì)列操作,以及其他堆棧和雙端隊(duì)列操作。
此實(shí)現(xiàn)不是同步的。
2.2.1構(gòu)造方法
LinkedList():構(gòu)造一個(gè)空的列表。
LinkedList(Collection<E> coll):構(gòu)造一個(gè)包含指定 collection 中的元素的列表,這些元素按其 collection 的迭代器返回的順序排列。
2.2.2 方法
E peek():獲取但不移除此列表的頭(第一個(gè)元素)。
E peekFirst():獲取但不移除此列表的第一個(gè)元素;如果此列表為空,則返回 null。
E peekLast():獲取但不移除此列表的最后一個(gè)元素;如果此列表為空,則返回 null。
E poll():獲取并移除此列表的頭(第一個(gè)元素)——E pollFirst()、E pollLast()
E pop():從此列表所表示的堆棧處彈出一個(gè)元素。
void push(E e):?將元素推入此列表所表示的堆棧。
boolean offer(E e):?將指定元素添加到此列表的末尾(最后一個(gè)元素)。——boolean offerFirst()、boolean offerLast()
2.3 Vector
可以實(shí)現(xiàn)可增長(zhǎng)的對(duì)象數(shù)組。Vector 是同步的
與數(shù)組一樣,它包含可以使用整數(shù)索引進(jìn)行訪問(wèn)的組件。但是,Vector 的大小可以根據(jù)需要增大或縮小,以適應(yīng)創(chuàng)建 Vector 后進(jìn)行添加或移除項(xiàng)的操作。
每個(gè)向量會(huì)試圖通過(guò)維護(hù) capacity 和 capacityIncrement 來(lái)優(yōu)化存儲(chǔ)管理。
- capacity 始終至少應(yīng)與向量的大小相等;這個(gè)值通常比后者大些,因?yàn)殡S著將組件添加到向量中,其存儲(chǔ)將按 capacityIncrement 的大小增加存儲(chǔ)塊。
- 應(yīng)用程序可以在插入大量組件前增加向量的容量;這樣就減少了增加的重分配的量。
2.3.1構(gòu)造方法
Vector():構(gòu)造一個(gè)空向量,使其內(nèi)部數(shù)據(jù)數(shù)組的大小為 10,其標(biāo)準(zhǔn)容量增量為零。
Vector(Collection<E> coll):構(gòu)造一個(gè)包含指定 collection 中的元素的向量,這些元素按其 collection 的迭代器返回元素的順序排列。
Vector(int initialCapacity):使用指定的初始容量和等于零的容量增量構(gòu)造一個(gè)空向量。
Vector(int initialCapacity, int capacityIncrement):使用指定的初始容量和容量增量構(gòu)造一個(gè)空的向量。
2.3.2方法
void copyInto(Object[] obj):將此向量的組件復(fù)制到指定的數(shù)組中。
void trimTosIZE():對(duì)此向量的容量進(jìn)行微調(diào),使其等于向量的當(dāng)前大小。
取出方法:枚舉Enumeration
沒(méi)有一個(gè)ArrayList的方法是同步的,而Vecotr的絕大多數(shù)方法(例如,add、insert、remove、set、equals、hashCode等)都是直接或間接同步的,所以Vector是線程安全的,ArrayList不是線程安全的。性能上ArrayList較好。
2.4總結(jié)
- 主要操作為:索引、只在集合末尾增刪元素——使用ArrayList和Vector
- 主要操作為:指定位置的插入刪除——LinkedList
- 多線程——Vector
3.Map接口
將鍵映射到值的對(duì)象。一個(gè)映射不能包含重復(fù)的鍵;每個(gè)鍵最多只能映射到一個(gè)值。
Map 接口提供三種collection 視圖,允許以鍵集、值集或鍵-值映射關(guān)系集的形式查看某個(gè)映射的內(nèi)容。
某些映射實(shí)現(xiàn)可明確保證其順序,如 TreeMap 類(lèi);另一些映射實(shí)現(xiàn)則不保證順序,如 HashMap 類(lèi)。
所有通用的映射實(shí)現(xiàn)類(lèi)應(yīng)該提供兩個(gè)“標(biāo)準(zhǔn)的”構(gòu)造方法:
- 一個(gè) void(無(wú)參數(shù))構(gòu)造方法,用于創(chuàng)建空映射;
- 一個(gè)是帶有單個(gè) Map 類(lèi)型參數(shù)的構(gòu)造方法,用于創(chuàng)建一個(gè)與其參數(shù)具有相同鍵-值映射關(guān)系的新映射。
- 實(shí)際上,后一個(gè)構(gòu)造方法允許用戶(hù)復(fù)制任意映射,生成所需類(lèi)的一個(gè)等價(jià)映射。
- 盡管無(wú)法強(qiáng)制執(zhí)行此建議(因?yàn)?span style="color:#3399ea;">接口不能包含構(gòu)造方法),但是 JDK 中所有通用的映射實(shí)現(xiàn)都遵從它。
3.1方法
boolean containsKey(Object key):如果此映射包含指定鍵的映射關(guān)系,則返回 true。
boolean containsVlue(Object value):?如果此映射將一個(gè)或多個(gè)鍵映射到指定值,則返回 true。
Set<Map,Entry<K,V>> enctrySet():返回此映射中包含的映射關(guān)系的 Set 視圖。
V get(Object key):?返回指定鍵所映射的值;如果此映射不包含該鍵的映射關(guān)系,則返回 null。
Set<K> getKey():?返回此映射中包含的鍵的 Set 視圖。
V put(K key,V value):??將指定的值與此映射中的指定鍵關(guān)聯(lián)(可選操作)。
Collections<V> values():?返回此映射中包含的值的 Collection 視圖。
3.2Map集合的遍歷
3.2.1鍵找值的方式
Set<String> keySet=map.keySet();Iterator<String> it=keySet.iterator();while(it.hasNext()){String key=it.next();String value=map.get(key); }3.2.2 Entry鍵值對(duì)對(duì)象
Entry:Map的內(nèi)部類(lèi)
將鍵值對(duì)封裝成了對(duì)象,可以從每個(gè)鍵值對(duì)對(duì)象獲取對(duì)應(yīng)的鍵和值。
步驟:
Map集合不能使用增強(qiáng)for進(jìn)行遍歷,但轉(zhuǎn)成Set后就可使用。
3.3HashMap
基于哈希表的 Map 接口的實(shí)現(xiàn)。此實(shí)現(xiàn)不是同步的。
允許使用 null 值和 null 鍵。(除了非同步和允許使用 null 之外,HashMap 類(lèi)與 Hashtable 大致相同。)
此類(lèi)不保證映射的順序。
HashMap 的實(shí)例有兩個(gè)參數(shù)影響其性能:初始容量 和加載因子。
- 容量 是哈希表中桶的數(shù)量,
- 初始容量只是哈希表在創(chuàng)建時(shí)的容量。
- 加載因子 (默認(rèn)是0.75)是哈希表在其容量自動(dòng)增加之前可以達(dá)到多滿(mǎn)的一種尺度。
- 當(dāng)哈希表中的條目數(shù)超出了加載因子與當(dāng)前容量的乘積時(shí),則要對(duì)該哈希表進(jìn)行 rehash 操作(即重建內(nèi)部數(shù)據(jù)結(jié)構(gòu)),從而哈希表將具有大約兩倍的桶數(shù)。
3.3.1構(gòu)造方法
HashMap():構(gòu)造一個(gè)具有默認(rèn)初始容量 (16) 和默認(rèn)加載因子 (0.75) 的空 HashMap。
?HashMap(int initialCapacity):構(gòu)造一個(gè)帶指定初始容量和默認(rèn)加載因子 (0.75) 的空 HashMap。
HashMap(int intialCapacity,float loadFactor):?構(gòu)造一個(gè)帶指定初始容量和加載因子的空 HashMap。
HashMap(Map<K,V> m):構(gòu)造一個(gè)映射關(guān)系與指定 Map 相同的新 HashMap。
3.3.2?HashMap添加元素
當(dāng)新增加的key的hash值已存在于HashMap中時(shí),會(huì)產(chǎn)生沖突。一般而言,對(duì)于不同的Key值可能會(huì)得到相同的hash值,所以應(yīng)對(duì)沖突進(jìn)行處理。處理沖突的方法:
- 開(kāi)放地址法;
- 再hash法;
- 鏈地址法。
3.3.3HashMap使用鏈地址法解決沖突的具體操作
3.3.4?向HashMap中添加元素時(shí),若遇到?jīng)_突,解決方式如圖
Object類(lèi)的equals()比較規(guī)則:當(dāng)參數(shù)obj引用的對(duì)象與當(dāng)前對(duì)象為同一個(gè)對(duì)象時(shí),就返回true,否則返回false。
hashCode()會(huì)返回對(duì)象存儲(chǔ)的內(nèi)存地址。
為了實(shí)現(xiàn)向HashMap中添加鍵值對(duì),可以根據(jù)對(duì)對(duì)象的內(nèi)容來(lái)判斷兩個(gè)對(duì)象是否相等,就需重寫(xiě)hashCode()和equals()。
import java.util.*;class Person{String id;String name;public int hachCode() {return id.hashCode();}public Person(String id,String name) {this.id=id;this.name=name;}public String toString() {return "id="+id+",name="+name;}public boolean equals(Object obj) {Person p=(Person)obj;if(p.id.equals(this.id))return true;elsereturn false;} }public class Test{public static void test() {System.out.println("Use String as key:");HashMap<Person,String> hm=new HashMap<Person,String>();Person p1=new Person("111","name1");Person p2=new Person("222","name2");hm.put(p1,"address1");hm.put(p2,"address2");Iterator iter=hm.entrySet().iterator();while(iter.hasNext()) {Map.Entry entry=(Map.Entry)iter.next();Person key=(Person)entry.getKey();String val=(String)entry.getValue();System.out.println("key:"+key+",value:"+val);}}public static void main(String[] args) {test();} }運(yùn)行結(jié)果
Use String as key:
key:id=111,name=name1,value:address1
key:id=222,name=name2,value:address2
使用自定義類(lèi)作為HahsMap的key時(shí),需注意:
3.3.5總結(jié)
根據(jù)鍵的hashCode值存儲(chǔ)數(shù)據(jù),由鍵可以很快得到它的值,訪問(wèn)速度快。
存的鍵值對(duì)沒(méi)有固定順序,取出時(shí)是隨機(jī)的。
適合在Map中插入、刪除和定位元素。
采用“強(qiáng)引用”,只有這個(gè)key從HashMap中刪除后,才能被垃圾回收器回收。
使用最多的。
3.4TreeMap
基于紅黑樹(shù)(Red-Black tree)的 NavigableMap 實(shí)現(xiàn)。此實(shí)現(xiàn)不是同步的。
實(shí)現(xiàn)了SortMap接口,能夠?qū)⒂涗?span style="color:#3399ea;">根據(jù)鍵值對(duì)排序保存,取出來(lái)時(shí)是排好序后的鍵值對(duì)。適用于需要按自然順序或自定義順序遍歷鍵。
該映射根據(jù)其鍵的自然順序進(jìn)行排序,或者根據(jù)創(chuàng)建映射時(shí)提供的 Comparator 進(jìn)行排序,具體取決于使用的構(gòu)造方法。?
此實(shí)現(xiàn)為 containsKey、get、put 和 remove 操作提供受保證的 log(n) 時(shí)間開(kāi)銷(xiāo)
3.4.2構(gòu)造方法
TreeMap():使用鍵的自然順序構(gòu)造一個(gè)新的、空的樹(shù)映射。
TreeMap(Comparator< K>?comparator):構(gòu)造一個(gè)新的、空的樹(shù)映射,該映射根據(jù)給定比較器進(jìn)行排序。
TreeMap(Map<K,V>?m):構(gòu)造一個(gè)與給定映射具有相同映射關(guān)系的新的樹(shù)映射,該映射根據(jù)其鍵的自然順序 進(jìn)行排序。
TreeMap((SortedMap<K,V>?m):構(gòu)造一個(gè)與指定有序映射具有相同映射關(guān)系和相同排序順序的新的樹(shù)映射。
3.4.3方法
Map.Entry<K,V> ceilingEntry(K key):返回一個(gè)鍵-值映射關(guān)系,它與大于等于給定鍵的最小鍵關(guān)聯(lián);如果不存在這樣的鍵,則返回 null。
K ceilingKey(K key):返回大于等于給定鍵的最小鍵;如果不存在這樣的鍵,則返回 null。
Map.Entry<K,V> higherEntry(K key):返回一個(gè)鍵-值映射關(guān)系,它與嚴(yán)格大于給定鍵的最小鍵關(guān)聯(lián);如果不存在這樣的鍵,則返回 null。
K higherKey(K key):返回嚴(yán)格大于給定鍵的最小鍵;如果不存在這樣的鍵,則返回 null。
lowerKey()、lowerEntry()
3.5?LinkedHashMap
HashMap的一個(gè)子類(lèi),按讀取順序排列,適用于需要輸入與輸出順序相同。
Map 接口的哈希表和鏈接列表實(shí)現(xiàn),具有可預(yù)知的迭代順序。此實(shí)現(xiàn)不是同步的
使用它可以生成一個(gè)與原來(lái)順序相同的映射副本,而與原映射的實(shí)現(xiàn)無(wú)關(guān):
void foo(Map m) {Map copy = new LinkedHashMap(m);... }提供特殊的構(gòu)造方法來(lái)創(chuàng)建鏈接哈希映射,該哈希映射的迭代順序就是最后訪問(wèn)其條目的順序,從近期訪問(wèn)最少到近期訪問(wèn)最多的順序(訪問(wèn)順序)。這種映射很適合構(gòu)建 LRU 緩存。
3.5.1構(gòu)造方法
LinkedHashMap():構(gòu)造一個(gè)帶默認(rèn)初始容量 (16) 和加載因子 (0.75) 的空插入順序 LinkedHashMap 實(shí)例
LinkedHashMap(int initialCapacity,int loadFactor,boolean accessOrder):構(gòu)造一個(gè)帶指定初始容量、加載因子和排序模式的空 LinkedHashMap 實(shí)例。
3.6 WeakHashaMap
與HashMap類(lèi)似,key采用“弱引用”的方式,在 WeakHashMap 中,當(dāng)某個(gè)鍵不再正常使用時(shí),將自動(dòng)移除其條目,被垃圾回收器回收。
- 對(duì)于一個(gè)給定的鍵,其映射的存在并不阻止垃圾回收器對(duì)該鍵的丟棄,這就使該鍵成為可終止的,被終止,然后被回收。
- 丟棄某個(gè)鍵時(shí),其條目從映射中有效地移除。
WeakHashMap 中的值對(duì)象由普通的強(qiáng)引用保持
null 值和 null 鍵都被支持。
該類(lèi)具有與 HashMap 類(lèi)相似的性能特征,并具有相同的效能參數(shù)初始容量 和加載因子。
不同步的。
3.7Hashtable
此類(lèi)實(shí)現(xiàn)一個(gè)哈希表,該哈希表將鍵映射到相應(yīng)的值。
任何非 null 對(duì)象都可以用作鍵或值。
為了成功地在哈希表中存儲(chǔ)和獲取對(duì)象,用作鍵的對(duì)象必須實(shí)現(xiàn) hashCode 方法和 equals 方法。
3.7.1構(gòu)造方法
Hashtable():用默認(rèn)的初始容量 (11) 和加載因子 (0.75) 構(gòu)造一個(gè)新的空哈希表。
3.7.2方法
?Enumeration<K> keys():返回此哈希表中的鍵的枚舉。
3.7.3示例
它將數(shù)字的名稱(chēng)用作鍵:
? Hashtable<String, Integer> numbers = new Hashtable<String, Integer>();numbers.put("one", 1);numbers.put("two", 2);numbers.put("three", 3);?要獲取一個(gè)數(shù)字,可以使用以下代碼:
Integer n = numbers.get("two"); if (n != null) {System.out.println("two = " + n); }3.8HashMap和HashTable
| HashMap | Hashtable |
| 是Hashtable的輕量級(jí)實(shí)現(xiàn)(非線程安全的實(shí)現(xiàn)) | 效率上,HashMap高于Hashtable |
| 都完成了Map接口 | 都完成了Map接口 |
| 允許空鍵值(key為null),最多只允許一條記錄的鍵為null | 不允許 |
| 去掉了Hashtable的contains方法,改成containsvalue和containsKey | ? |
| java 1.2引進(jìn)的Map interface的一個(gè)實(shí)現(xiàn) | 繼承自Dictionary類(lèi) |
| 不支持線程同步,所以不是線程安全的 | 線程安全的 |
| 使用Iterator | 使用Enumeration |
| hash數(shù)組默認(rèn)大小是16,而且一定是2的指數(shù) | hash默認(rèn)大小是11,增加方式是old*2+1; |
| hash值的使用不同 | Hashtable使用對(duì)象的hashCode |
使用自定義類(lèi)型作為HashMap或Hashtable的key需注意:
- 不能存儲(chǔ)重復(fù)的鍵,當(dāng)有重復(fù)的鍵時(shí),不會(huì)創(chuàng)建新的映射關(guān)系,而是使用先前的鍵值;
總結(jié)
以上是生活随笔為你收集整理的集合-2(Set(HashSet、TreeSet、LinkedHashSet)、List(ArrayList、LinkedList、Vector)、Map(HashMap、TreeMap...))的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 集合-1(Collection、迭代器、
- 下一篇: 类加载器、双亲委派模型