文章目錄
- 1.List,Map,Set存取的特點
- 2.ArrayList、Vector、LinkedList的存盤性能和特性
- 3.ArrayList和LinkedList的區別
- 4.HashMap和Hashtable的區別
- 4.1繼承的父類不同
- 4.2執行緒安全性不同
- 4.3key和value是否允許null值
- 4.4內部實作使用的陣列初始化和擴容方式不同
- 4.5迭代器不同
- 5.快速失敗(fail-fast)和安全失敗(fail-safe)的區別
- 6.Iterator和ListIterator的區別
- 6.1ListIterator 繼承自 Iterator 介面,在 Iterator 的基礎上增加了 6 個方法:
- 6.2ListIterator 有兩種獲取方式
- 7.什么是迭代器
- 8.類和介面的關系
1.List,Map,Set存取的特點
- List
- 可以有重復元素
- 以特定索引保存
- Map和Set
- 可以一對一和多對一
- 有哈希存盤和排序樹兩個版本

2.ArrayList、Vector、LinkedList的存盤性能和特性
- ArrayList 和Vector
- 都是使用陣列方式存盤資料
- 都允許直接按序號索引元素
- Vector是執行緒安全的容器,添加了synchronized修飾,但性能上較ArrayList差
- LinkedList使用雙向鏈表實作存盤
- 可以按序號索引的線性結構,這種鏈式存盤方式與陣列的連續存盤方式相比,記憶體的利用率更高
- 插入資料時只需要記錄本項的前后項即可,所以插入速度較快
3.ArrayList和LinkedList的區別
都實作了List介面,LinkedList比ArrayList更占記憶體,因為LinkedList為每一個節點存盤了兩個參考,一個指向前一個元素,一個指向下一個元素,
- ArrayList是基于索引的資料介面,它的底層是陣列,它可以以O(1)時間復雜度對元素進行隨機訪問,與此對應,LinkedList是以元素串列的形式存盤它的資料,每一個元素都和它的前一個和后一個元素鏈接在一起,在這種情況下,查找某個元素的時間復雜度是O(n),
- LinkedList的插入,添加,洗掉操作速度更快,因為當元素被添加到集合任意位置的時候,不需要像陣列那樣重新計算大小或者是更新索引,
4.HashMap和Hashtable的區別
HashMap和Hashtable都實作了Map介面,因此很多特性非常相似,但是,他們有以下不同點:
4.1繼承的父類不同
Hashtable繼承自Dictionary類,
HashMap繼承自AbstractMap類,
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable {}
public class Hashtable<K,V>
extends Dictionary<K,V>
implements Map<K,V>, Cloneable, java.io.Serializable {}
4.2執行緒安全性不同
- HashMap是執行緒不安全的
- HashTable是執行緒安全的
public synchronized void putAll(Map<? extends K, ? extends V> t) {
for (Map.Entry<? extends K, ? extends V> e : t.entrySet())
put(e.getKey(), e.getValue());
}
/**
* Clears this hashtable so that it contains no keys.
*/
public synchronized void clear() {
Entry<?,?> tab[] = table;
modCount++;
for (int index = tab.length; --index >= 0; )
tab[index] = null;
count = 0;
}
4.3key和value是否允許null值
- Hashtable中,key和value都不允許出現null值,但是如果在Hashtable中有類似put(null,null)的操作,編譯同樣可以通過,因為key和value都是Object型別,但運行時會拋出
NullPointerException例外,這是JDK的規范規定的, - HashMap中,null可以作為鍵,這樣的鍵只有一個;可以有一個或多個鍵所對應的值為null,當get()方法回傳null值時,可能是 HashMap中沒有該鍵,也可能使該鍵所對應的值為null,因此,在HashMap中不能由get()方法來判斷HashMap中是否存在某個鍵,而應該用containsKey()方法來判斷,
4.4內部實作使用的陣列初始化和擴容方式不同
-
HashTable在不指定容量的情況下的默認容量為11,而HashMap為16,Hashtable不要求底層陣列的容量一定要為2的整數次冪,而HashMap則要求一定為2的整數次冪,
-
Hashtable擴容時,將容量變為原來的2倍加1,而HashMap擴容時,將容量變為原來的2倍,
- 將哈希表的大小固定為了2的冪,因為是取模得到索引值,故這樣取模時,不需要做除法,只需要做位運算,位運算比除法的效率要高很多,
- 擴容resize()的時候,原來哈希表中,有接近一半的節點的下標是不變的,而另外的一半的下標為 原來的length + 原來的下標,具體要看hash值對應擴容后的某一位是0還是1.
4.5迭代器不同
- HashMap 中的 Iterator 迭代器是 fail-fast 的
- Hashtable 的 Enumerator 不是 fail-fast 的,
快速失敗(fail—fast)是java集合中的一種機制, 在用迭代器遍歷一個集合物件時,如果遍歷程序中對集合物件的內容進行了修改(增加、洗掉、修改),則會拋出Concurrent Modification Exception,
5.快速失敗(fail-fast)和安全失敗(fail-safe)的區別
Iterator的安全失敗是基于對底層集合做拷貝,因此,它不受源集合上修改的影響,
快速失敗(fail-fast )是java集合中的一種機制,在用迭代器遍歷一個集合物件時,如果遍歷程序中對集合物件的內容進行了修改(增加,洗掉,修改),則會拋出
ConcurrentModification Exception,
- java.util包下面的所有的集合類都是快速失敗的
- java.util.concurrent包下面的所有的類都是安全失敗的,
- 快速失敗的迭代器會拋出
ConcurrentModificationException例外,而安全失敗的迭代器永遠不會拋出這樣的例外,
找一下HashMap的原始碼,有一個int 型別的變數modCount,
/**
* The number of times this HashMap has been structurally modified
* Structural modifications are those that change the number of mappings in
* the HashMap or otherwise modify its internal structure (e.g.,
* rehash). This field is used to make iterators on Collection-views of
* the HashMap fail-fast. (See ConcurrentModificationException).
*/
transient int modCount;
-
迭代器在遍歷時直接訪問集合中的內容,并且在遍歷程序中使用一個 modCount 變數,
-
集合在被遍歷期間如果內容發生變化,就會改變modCount的值,
-
每當迭代器使用hashNext()/next()遍歷下一個元素之前,都會檢測modCount變數是否為expectedmodCount值,是的話就回傳遍歷;否則拋出例外,終止遍歷,
Tip:這里例外的拋出條件是檢測到 modCount!=expectedmodCount 這個條件,如果集合發生變化時修改modCount值剛好又設定為了expectedmodCount值,則例外不會拋出,
因此,不能依賴于這個例外是否拋出而進行并發操作的編程,這個例外只建議用于檢測并發修改的bug,

6.Iterator和ListIterator的區別
- Iterator可用來遍歷Set和List集合,但是ListIterator只能用來遍歷List,
- Iterator對集合只能是前向遍歷,ListIterator既可以前向也可以后向,
- ListIterator繼承了Iterator介面,并包含其他的功能,比如:增加元素,替換元素,獲取前一個和后一個元素的索引,等等,
6.1ListIterator 繼承自 Iterator 介面,在 Iterator 的基礎上增加了 6 個方法:

- void hasPrevious()
- 判斷游標前面是否有元素;
- Object previous()
- 回傳游標前面的元素,同時游標前移一位,游標前沒有元素就報 java.util.NoSuchElementException 的錯,所以使用前最好判斷一下;
- int nextIndex()
- 回傳游標后邊元素的索引位置,初始為 0 ;遍歷 N 個元素結束時為 N;
- int previousIndex()
- 回傳游標前面元素的位置,初始時為 -1,同時報
java.util.NoSuchElementException錯;
- 回傳游標前面元素的位置,初始時為 -1,同時報
- void add(E)
- 在游標 前面 插入一個元素
注意,是前面
- 在游標 前面 插入一個元素
- void set(E)
- 更新迭代器最后一次操作的元素為 E,也就是更新最后一次呼叫 next() 或者 previous() 回傳的元素,
- 注意,當沒有迭代,也就是沒有呼叫 next() 或者 previous() 直接呼叫 set 時會報
java.lang.IllegalStateException錯;
- void remove()
- 洗掉迭代器最后一次操作的元素,注意事項和 set 一樣,
6.2ListIterator 有兩種獲取方式
- List.listIterator()
- List.listIterator(int location)
第二種可以指定 游標的所在位置,
7.什么是迭代器
- Iterator提供了統一遍歷操作集合元素的統一介面, Collection介面也是繼承Iterable介面.
每個集合都通過實作Iterable介面中iterator()方法回傳Iterator介面的實體,然后對集合的元素進行迭代操作.
有一點需要注意的是:在迭代元素的時候不能通過集合的方法洗掉元素, 否則會拋出ConcurrentModificationException例外. 但是可以通過Iterator介面中的remove()方法進行洗掉.
8.類和介面的關系
- 類和類:類繼承類,單繼承,多層繼承
- 類和介面:類實作介面,可實作多個介面,介面名之間用逗號隔開
- 介面和介面:介面繼承介面,多繼承,為了彌補java中類的單繼承特點
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/266330.html
標籤:其他
上一篇:雪花演算法代碼
