0.鏈表,隊列和棧的區別?
- 鏈表是一種存儲結構,指得是存儲時候除了要存儲數據元素之外,還要用數據元素一起的另外空間存儲數據元素的關系。
- 隊列和棧都是線性表,屬於邏輯結構范疇,都是訪問點受到限制,並且限制在線性表端點的線性表。
- 棧被限定為在線性表中的同一個(唯一一個的)端點插入刪除
- 隊列被限定為在線性表的一端插入,另外一個端點刪除
- 棧和隊列也可以用鏈表來實現,分別稱為鏈棧和鏈隊列
1. ArrayList
- ArrayList是基於數組實現的,最大長度不會超過數組的長度2147483647(最大值是int的最大值是,2的31次方減去1 ).如果業務中可能存在超過這個長度的數據,使用LinkedArrayList
3.HashMap
Java中的HashMap是以鍵值對(key-value)的形式存儲元素的。HashMap需要一個hash函數,它使用hashCode()和equals()方法來向集合/從集合添加和檢索元素。當調用put()方法的時候,HashMap會計算key的hash值,然后把鍵值對存儲在集合中合適的索引上。如果key已經存在了,value會被更新成新值。
HashMap的一些重要的特性是它的容量(capacity),負載因子(load factor)和擴容極限(threshold resizing)。
4.HashMap和HashTable的區別?
- >繼承不同。 public class Hashtable extends Dictionary implements Map public class HashMap extends AbstractMap implements Map
- >Hashtable 中的方法是同步的,而HashMap中的方法在缺省情況下是非同步的。在多線程並發的環境下,可以直接使用Hashtable,但是要使用HashMap的話就要自己增加同步處理了。
- >Hashtable中,key和value都不允許出現null值。在HashMap中,null可以作為鍵,這樣的鍵只有一個;可以有一個或多個鍵所對應的值為null。當get()方法返回null值時,即可以表示 HashMap中沒有該鍵,也可以表示該鍵所對應的值為null。因此,在HashMap中不能由get()方法來判斷HashMap中是否存在某個鍵, 而應該用containsKey()方法來判斷。
- > 兩個遍歷方式的內部實現上不同。Hashtable、HashMap都使用了 Iterator。而由於歷史原因,Hashtable還使用了Enumeration的方式 。
- >哈希值的使用不同,HashTable直接使用對象的hashCode。而HashMap重新計算hash值。
- >Hashtable和HashMap它們兩個內部實現方式的數組的初始大小和擴容的方式。HashTable中hash數組默認大小是11,增加的方式是 old*2+1。HashMap中hash數組的默認大小是16,而且一定是2的指數。
5.Java集合類里面最基本的接口有:
- Collection:代表一組對象,每一個對象都是它的子元素。
- Set:不包含重復元素的Collection。
- List:有順序的collection,並且可以包含重復元素。
- Map:可以把鍵(key)映射到值(value)的對象,鍵不能重復。
6.什么是迭代器(Iterator)?
Iterator接口提供了很多對集合元素進行迭代的方法。每一個集合類都包含了可以返回迭代器實例的迭代方法。迭代器可以在迭代的過程中刪除底層集合的元素。
7.Iterator和ListIterator的區別是什么?
- Iterator可用來遍歷Set和List集合,但是ListIterator只能用來遍歷List。
- Iterator對集合只能是前向遍歷,ListIterator既可以前向也可以后向。
- ListIterator實現了Iterator接口,並包含其他的功能,比如:增加元素,替換元素,獲取前一個和后一個元素的索引,等等。
8.Enumeration接口和Iterator接口的區別有哪些?
Enumeration速度是Iterator的2倍,同時占用更少的內存。但是,Iterator遠遠比Enumeration安全,因為其他線程不能夠修改正在被iterator遍歷的集合里面的對象。同時,Iterator允許調用者刪除底層集合里面的元素,這對Enumeration來說是不可能的。
9.快速失敗(fail-fast)和安全失敗(fail-safe)的區別是什么?
-
fail-fast機制在遍歷一個集合時,當集合結構被修改,會拋出Concurrent Modification Exception。 > fail-fast會在以下兩種情況下拋出ConcurrentModificationException : >> 1. 單線程環境:集合被創建后,在遍歷它的過程中修改了結構。 >>>> <font color=red size=2>注意 remove()方法會讓expectModcount和modcount 相等,所以是不會拋出這個異常。</font> >> 2. 多線程環境: 當一個線程在遍歷這個集合,而另一個線程對這個集合的結構進行了修改。 >>> <font color=red size=2>注意,迭代器的快速失敗行為無法得到保證,因為一般來說,不可能對是否出現不同步並發修改做出任何硬性保證。快速失敗迭代器會盡最大努力拋出 ConcurrentModificationException。因此,為提高這類迭代器的正確性而編寫一個依賴於此異常的程序是錯誤的做法:迭代器的快速失敗行為應該僅用於檢測 bug。</font> > fail-fast機制是如何檢測的? >> 迭代器在遍歷過程中是直接訪問內部數據的,因此內部的數據在遍歷的過程中無法被修改。為了保證不被修改,迭代器內部維護了一個標記 “mode” ,當集合結構改變(添加刪除或者修改),標記"mode"會被修改,而迭代器每次的hasNext()和next()方法都會檢查該"mode"是否被改變,當檢測到被修改時,拋出Concurrent Modification Exception
-
fail-safe任何對集合結構的修改都會在一個復制的集合上進行修改,因此不會拋出ConcurrentModificationException > * fail-safe機制有兩個問題 > 1. 需要復制集合,產生大量的無效對象,開銷大 > 2. 無法保證讀取的數據是目前原始數據結構中的數據。
10.ArrayList和LinkedList有什么區別?
ArrayList和LinkedList都實現了List接口,他們有以下的不同點: 1. ArrayList是基於索引的數據接口,它的底層是數組。它可以以O(1)時間復雜度對元素進行隨機訪問。與此對應,LinkedList是以元素列表的形式存儲它的數據,每一個元素都和它的前一個和后一個元素鏈接在一起,在這種情況下,查找某個元素的時間復雜度是O(n)。 2. 相對於ArrayList,LinkedList的插入,添加,刪除操作速度更快,因為當元素被添加到集合任意位置的時候,不需要像數組那樣重新計算大小或者是更新索引。
- LinkedList比ArrayList更占內存,因為LinkedList為每一個節點存儲了兩個引用,一個指向前一個元素,一個指向下一個元素。
11.什么是Java優先級隊列(Priority Queue)?
- PriorityQueue類在Java1.5中引入並作為 Java Collections Framework 的一部分。PriorityQueue是基於優先堆的一個無界隊列,這個優先隊列中的元素可以默認自然排序或者通過提供的Comparator(比較器)在隊列實例化的時排序。
- 優先隊列不允許空值,而且不支持non-comparable(不可比較)的對象,比如用戶自定義的類。優先隊列要求使用Java Comparable和Comparator接口給對象排序,並且在排序時會按照優先級處理其中的元素。
- 優先隊列的頭是基於自然排序或者Comparator排序的最小元素。如果有多個對象擁有同樣的排序,那么就可能隨機地取其中任意一個。當我們獲取隊列時,返回隊列的頭對象
- 優先隊列的大小是不受限制的,但在創建時可以指定初始大小。當我們向優先隊列增加元素的時候,隊列大小會自動增加。
- PriorityQueue是非線程安全的,所以Java提供了PriorityBlockingQueue(實現BlockingQueue接口)用於Java多線程環境。
<font color=red size=2>說明:有界隊列是一種特殊隊列,當隊列為空時,隊列的獲取操作將會阻塞獲取線程,直到隊列中有新增元素;當隊列已滿時,隊列的插入操作會阻塞插入線程,直到隊列中出現空位。 無界隊列與有界隊列相比,除非系統資源耗盡,否則無界的任務隊列不存在任務入隊失敗的情況。 </font>
12.Java集合類框架的最佳實踐有哪些?
-
根據應用的需要正確選擇要使用的集合的類型對性能非常重要,比如:假如元素的大小是固定的,而且能事先知道,我們就應該用Array而不是ArrayList。
-
有些集合類允許指定初始容量。因此,如果我們能估計出存儲的元素的數目,我們可以設置初始容量來避免重新計算hash值或者是擴容。
-
為了類型安全,可讀性和健壯性的原因總是要使用泛型。同時,使用泛型還可以避免運行時的ClassCastException。
-
使用JDK提供的不變類(immutable class)作為Map的鍵可以避免為我們自己的類實現hashCode()和equals()方法。
-
編程的時候接口優於實現。
-
底層的集合實際上是空的情況下,返回長度是0的集合或者是數組,不要返回null。
13.HashSet和TreeSet有什么區別?
-
HashSet是由一個hash表來實現的,因此,它的元素是無序的。add(),remove(),contains()方法的時間復雜度是O(1)。
-
另一方面,TreeSet是由一個樹形的結構來實現的,它里面的元素是有序的。因此,add(),remove(),contains()方法的時間復雜度是O(logn)。
14.TreeMap和TreeSet在排序時如何比較元素?Collections工具類中的sort()方法如何比較元素?
- TreeSet要求存放的對象所屬的類必須實現Comparable接口,該接口提供了比較元素的compareTo()方法,當插入元素時會回調該方法比較元素的大小。
- TreeMap要求存放的鍵值對映射的鍵必須實現Comparable接口從而根據鍵對元素進行排序。
- Collections工具類的sort方法有兩種重載的形式,第一種要求傳入的待排序容器中存放的對象比較實現Comparable接口以實現元素的比較;第二種不強制性的要求容器中的元素必須可比較,但是要求傳入第二個參數,參數是Comparator接口的子類型(需要重寫compare方法實現元素的比較),相當於一個臨時定義的排序規則,其實就是通過接口注入比較元素大小的算法,也是對回調模式的應用(Java中對函數式編程的支持)。
15.ArrayList和Vector的區別
這兩個類都實現了List接口(List接口繼承了Collection接口),他們都是有序集合,即存儲在這兩個集合中的元素的位置都是有順序的,相當於一種動態的數組,我們以后可以按位置索引號取出某個元素,並且其中的數據是允許重復的,這是與HashSet之類的集合的最大不同處,HashSet之類的集合不可以按索引號去檢索其中的元素,也不允許有重復的元素。 * ArrayList與Vector的區別主要包括兩個方面:. 1. 同步性:Vector是線程安全的,也就是說是它的方法之間是線程同步的,而ArrayList是線程序不安全的,它的方法之間是線程不同步的。如果只有一個線程會訪問到集合,那最好是使用ArrayList,因為它不考慮線程安全,效率會高些;如果有多個線程會訪問到集合,那最好是使用Vector,因為不需要我們自己再去考慮和編寫線程安全的代碼。 2. 數據增長:ArrayList與Vector都有一個初始的容量大小,當存儲進它們里面的元素的個數超過了容量時,就需要增加ArrayList與Vector的存儲空間,每次要增加存儲空間時,不是只增加一個存儲單元,而是增加多個存儲單元,每次增加的存儲單元的個數在內存空間利用與程序效率之間要取得一定的平衡。Vector默認增長為原來兩倍,而ArrayList的增長策略在文檔中沒有明確規定(從源代碼看到的是增長為原來的1.5倍)。ArrayList與Vector都可以設置初始的空間大小,Vector還可以設置增長的空間大小,而ArrayList沒有提供設置增長空間的方法。
總結:即Vector增長原來的一倍,ArrayList增加原來的0.5倍。