java面試題之集合篇
List(有序、可重複)
List裡存放的物件是有序的,同時也是可以重複的,List關注的是索引,擁有一系列和索引相關的方法,查詢速度快。因為往list集合裡插入或刪除資料時,會伴隨著後面資料的移動,所有插入刪除資料速度慢。
實現了List介面的類
ArrayList、LinkedList、Vector
Set(無序、不能重複)
Set裡存放的物件是無序,不能重複的,集合中的物件不按特定的方式排序,只是簡單地把物件加入集合中。
實現了Set介面的類
HashSet、LinkedHashSet、TreeSet
Java中Set與List有什麼不同?
Set是一個不允許重複元素存在的集合
Set沒有索引
Set僅僅允許一個null值
List有索引
List允許N個null值
List可以按插入順序顯示
Arraylist與Vector的區別?
Vector 在Java的第一個版本就引入了,也就是說Vector是一個合法規範的類。
ArrayList在Java1.2版本引入的,是Java 集合框架的組成部分。
Vector是同步的,ArrayList是不同步的。
為什麼Map介面不繼承Collection 介面?
Set是無序集合,並且不允許重複的元素。
List是有序的集合,並且允許重複的元素。
而Map是鍵值對,它被視為是鍵的set和值的set的組合。
Map被設計為鍵值對的集合,所以不需要繼承Collection 介面。
List和Map的實現方式以及儲存方式
List使用可變長陣列實現方式
Map使用陣列加連結串列的資料結構實現
Comparable和Comparator的不同之處?
Comparable和Comparator介面被用來對物件集合或者陣列進行排序。
Comparable介面被用來提供物件的自然排序,我們可以使用它來提供基於單個邏輯的排序。
Comparator介面被用來提供不同的排序演算法,我們可以選擇需要使用的Comparator來對給定的物件集合進行排序。
如何對Object的list排序?
對objects陣列進行排序,我們可以用Arrays.sort()方法
如果要對objects的集合進行排序,需要使用Collections.sort()方法。
fail-fast與fail-safe之間的區別?
fail-fast快速地報告任何的failure。無論何時任何一個問題都會引發 fail-fast系統fails。
在Java fail fast 迭代器中,迭代objects集合有時會出現併發修改異常,出現這種情況有2個原因。如果一個執行緒正在迭代一個集合,而另一個執行緒同時試圖修改這個集合,在呼叫remove()方法後,如何我們還試圖去修改集合object
fail-safe任何對集合結構的修改都會在一個複製的集合上進行修改,因此不會丟擲ConcurrentModificationException
Iterator、ListIterator 和 Enumeration的區別?
Enumeration介面在Java1.2版本開始有,所以Enumeration是合法規範的介面。
Enumeration使用elements()方法。
Iterator對所有Java集合類都有實現
Iterator使用iterator方法
Iterator只能往一個方向前進
ListIterator僅僅對List型別的類實現了
ListIterator使用listIterator()方法
為什麼Collection不能繼承Cloneable和Serializable?
Collection表示一個集合,包含了一組物件。如何儲存和維護這些物件是由具體實現來決定的。因為集合的具體形式多種多樣,例如list允許重複,set則不允許。而克隆(clone)和序列化(serializable)只對於具體的實體,物件有意義,你不能說去把一個介面,抽象類克隆,序列化甚至反序列化。所以具體的collection實現類是否可以克隆,是否可以序列化應該由其自身決定,而不能由其超類強行賦予。
如果collection繼承了clone和serializable,那麼所有的集合實現都會實現這兩個介面,而如果某個實現它不需要被克隆,甚至不允許它序列化(序列化有風險),那麼就與collection矛盾了。
能否使用任何類作為Map的key?
可以使用任何類作為Map的key,然而在使用它們之前,需要考慮以下幾點:
(1)如果類重寫了equals()方法,它也應該重寫hashCode()方法。
(2)類的所有例項需要遵循與equals()和hashCode()相關的規則。請參考之前提到的這些規則。
(3)如果一個類沒有使用equals(),你不應該在hashCode()中使用它。
(4)使用者自定義key類的最佳實踐是使之為不可變的,這樣,hashCode()值可以被快取起來,擁有更好的效能。不可變的類也可以確保hashCode()和equals()在未來不會改變,這樣就會解決與可變相關的問題了。
是否可以往TreeSet或者HashSet中新增null元素?
可以往HashSet中新增一個null
TreeSet也允許一個null值
ArrayMap和HashMap的對比
ArrayMap是一個< key,value > 對映的資料結構,它設計上更多的是考慮記憶體的優化,內部是使用兩個陣列進行資料儲存,一個數組記錄key的hash值,另外一個數組記錄Value值,它和SparseArray一樣,也會對key使用二分法進行從小到大排序,在新增、刪除、查詢資料的時候都是先使用二分查詢法得到相應的index,然後通過index來進行新增、查詢、刪除等操作。
(1)儲存方式不同
HashMap內部有一個HashMapEntry<K, V>[]物件,每一個鍵值對都儲存在這個物件裡,當使用put方法新增鍵值對時,就會new一個HashMapEntry物件。
(2)新增資料時擴容時的處理不一樣。HashMap重新建立物件,開銷很大。ArrayMap用的是copy資料,所以效率相對要高。
(3)ArrayMap提供了陣列收縮的功能,在clear或remove後,會重新收縮陣列,釋放空間。
(4) ArrayMap採用二分法查詢
HashMap和HashTable的區別
(1)HashMap允許key和value為null,而HashTable不允許。
(2)HashTable是同步的,而HashMap不是。所以HashMap適合單執行緒環境,HashTable適合多執行緒環境。
(3)在Java1.4中引入了LinkedHashMap,HashMap的一個子類,假如你想要遍歷順序,你很容易從HashMap轉向LinkedHashMap,但是HashTable不是這樣的,它的順序是不可預知的。
(4)HashMap提供對key的Set進行遍歷,因此它是fail-fast的,但HashTable提供對key的Enumeration進行遍歷,它不支援fail-fast。
(5)HashTable被認為是個遺留的類,如果你尋求在迭代的時候修改Map,你應該使用CocurrentHashMap。
HashMap與HashSet的區別
(1)HashMap實現了Map介面HashSet實現了Set介面。
(2)HashMap儲存鍵值對,HashSet僅僅儲存物件使用put()方法將元素放入map中,使用add()方法將元素放入set中。
(3)HashMap中使用鍵物件來計算hashcode值 HashSet使用成員物件來計算hashcode值,對於兩個物件來說hashcode可能相同,所以equals()方法用來判斷物件的相等性,如果兩個物件不同的話,那麼返回false。
(4)HashMap比較快,因為是使用唯一的鍵來獲取物件 HashSet較HashMap來說比較慢
HashSet怎麼判斷集合元素重複?
HashSet不能新增重複的元素,當呼叫add(Object)方法時候,首先會呼叫Object的hashCode方法判hashCode是否已經存在,如不存在則直接插入元素;如果已存在則呼叫Object物件的equals方法判斷是否返回true,如果為true,則說明元素已經存在,如為false,則插入元素。
ArrayList和LinkedList的區別,以及應用場景
(1)ArrayList是由Array所支援的基於一個索引的資料結構,所以它提供對元素的隨機訪問,複雜度為O(1),但LinkedList儲存一系列的節點資料,每個節點都與前一個和下一個節點相連線。所以,儘管有使用索引獲取元素的方法,內部實現是從起始點開始遍歷,遍歷到索引的節點然後返回元素,時間複雜度為O(n),比ArrayList要慢。
(2)與ArrayList相比,在LinkedList中插入、新增和刪除一個元素會更快,因為在一個元素被插入到中間的時候,不會涉及改變陣列的大小,或更新索引。
(3)LinkedList比ArrayList消耗更多的記憶體,因為LinkedList中的每個節點儲存了前後節點的引用。
哪些集合類是執行緒安全的?
Vector、HashTable、Properties和Stack是同步類,所以它們是執行緒安全的,可以在多執行緒環境下使用。Java1.5併發API包括一些集合類,允許迭代時修改,因為它們都工作在集合的克隆上,所以它們在多執行緒環境中是安全的。
如何保證一個集合執行緒安全?
使用Collections.synchronizedList(list)) 方法,可以保證list類是執行緒安全的。
使用java.util.Collections.synchronizedSet()方法可以保證set類是執行緒安全的。
併發集合類是什麼?
Java1.5併發包(java.util.concurrent)包含執行緒安全集合類,允許在迭代時修改集合。迭代器被設計為fail-fast的,會丟擲ConcurrentModificationException。一部分類為:CopyOnWriteArrayList、 ConcurrentHashMap、CopyOnWriteArraySet。
BlockingQueue是什麼?
Java.util.concurrent.BlockingQueue是一個佇列,在進行檢索或移除一個元素的時候,它會等待佇列變為非空;當在新增一個元素時,它會等待佇列中的可用空間。BlockingQueue介面是Java集合框架的一部分,主要用於實現生產者-消費者模式。我們不需要擔心等待生產者有可用的空間,或消費者有可用的物件,因為它都在BlockingQueue的實現類中被處理了。Java提供了集中BlockingQueue的實現,比如ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue,、SynchronousQueue等。
陣列和連結串列的區別
陣列結構 :
陣列結構在通過索引進行查詢資料時效率比較高,而對於陣列插入和刪除操作,則效率會比較低,在第一個位置進行插入資料,其餘資料就需要依次向後移動,而第一個資料進行刪除,則需要所有資料全部向前移,這樣的話,就會推出第二種結構,連結串列結構。
連結串列:
連結串列是由一系列節點組成的,每個節點都會有一個鏈點,這就是next鏈,而next鏈則會執行下一個node的引用,所以我們在插入或者刪除的時候,需要該錶鏈表next鏈的指向地址即可,每個節點不需要記憶體進行連續儲存,這樣會減小刪除和插入的線性開銷。
什麼是深拷貝和淺拷貝
淺拷貝:
淺拷貝又叫淺複製,將物件中的所有欄位複製到新的物件(副本)中。其中,值型別欄位(java中8中原始型別)的值被複制到副本中後,在副本中的修改不會影響到源物件對應的值。而引用型別的欄位被複制到副本中的還是引用型別的引用,而不是引用的物件,在副本中對引用型別的欄位值做修改會影響到源物件本身。
深拷貝:
深拷貝將物件中的所有欄位複製到新的物件中。不過,無論是物件的值型別欄位,還是引用型別欄位,都會被重新建立並賦值,對於副本的修改,不會影響到源物件本身。
好了,本篇文章就分享到這裡了。有興趣的新手夥伴們可以關注收藏起來,以後需要的時候可以多看看。如果有正在學java的程式設計師,可來我們的java技術學習扣qun哦:59789,1510裡面免費送java的視訊系統教程!