
89. ArrayList 與 LinkedList 有何不同?
這是最常見的問題之一,還有關於 HashMap 內部結構的問題。沒有它,面試就不完整,所以你的答案應該很容易脫口而出。除了明顯的差異(它們有不同的名稱)之外,它們的內部結構也有所不同。之前,我們討論了ArrayList和LinkedList的內部結構,因此我不會深入討論它們的實作細節。我只是提醒您,ArrayList是使用內部數組實現的,其大小根據以下公式動態增加:
<size of the current array> * 3 / 2 + 1
此外, LinkedList 的實作使用內部雙向鍊錶,即每個元素都有對前一個和下一個元素的引用,但列表開頭和結尾的元素除外。面試官喜歡問這樣的問題:“ ArrayList和LinkedList哪個更好?” 希望能抓住你。畢竟,如果你說其中一個更好,那麼你就給了錯誤的答案。 
-
如果未指定索引,則新項目將自動新增至兩種清單的末端。在LinkedList中,新元素將成為新尾部(只會重寫一對引用,因此演算法複雜度為O(1))。
add 方法將一個元素加入到陣列中的最後一個空單元格 ( O(1) )。
-
透過索引添加項目通常意味著將其插入清單中間的某個位置。在LinkedList中,該方法將首先透過迭代尾部和頭部的元素來搜尋所需的位置 ( O(n/2) ),然後透過覆蓋兩側元素的參考來插入值插入新元素 ( O(1) )。此操作的總體演算法複雜度將為O(n/2)。
在相同的情況下(按索引新增),ArrayList找到所需的位置(O(1)),然後將位於右側的所有元素(包括已儲存在指定索引處的元素)向右移動一位(這可能需要建立一個新的內部陣列並將元素複製到其中)(O(n/2))。總體複雜度為O(n/2)。
-
將元素添加到LinkedList的開頭類似於將元素添加到末尾:新元素成為新頭 ( O(1) )。但對於 ArrayList,該操作需要將所有元素移到右側 ( O(n) )。
90. ArrayList 與 HashSet 有何不同?
如果我們可以逐一比較ArrayList和LinkedList以確定哪一個比較好,那麼我們會發現在ArrayList和HashSet之間進行這樣的比較就沒那麼容易了,因為它們是完全不同的集合。你可以將一種甜點與另一種甜點進行比較,但比較甜點和鹹味菜餚是一項挑戰——它們截然不同。儘管如此,我還是會試著指出它們之間的一些差異:-
ArrayList實作了List接口,而HashSet實作了Set接口。
-
ArrayList允許您透過索引存取元素:get操作的演算法複雜度為O(1),但HashSet只允許您透過迭代存取所需的元素,這會產生從O(1)到O(n) 的演算法複雜度。
-
ArrayList允許重複元素。在HashSet中,所有元素都是唯一的:任何已添加 HashSet 中已存在的元素的嘗試都會失敗(透過雜湊碼檢查重複項,因此該集合的名稱也由此而來)。
-
ArrayList是使用內部陣列實現的,而HashSet是使用內部HashMap實現的。
-
ArrayList維護元素的插入順序,但HashSet是無序集合,不維護元素的順序。
-
ArrayList允許任意數量的空值,但你只能在HashSet中加入一個空值(畢竟元素必須是唯一的)。
91. 為什麼Java有這麼多不同的動態陣列實作?
這更多的是一個哲學問題。我們也可以問為什麼他們會想出這麼多新奇的技術?為了方便。對於大量動態數組實作也是如此。它們都不能被稱為最好或理想的實現。每種情況都有其優點。我們的工作是了解它們的差異以及它們的優點/缺點,以便能夠使用最適合任何特定情況的集合。92. 為什麼Java有這麼多不同的鍵值儲存實作?
這裡的情況與動態數組實現相同。絕對沒有一個是普遍優於其他的:每個都有優點和缺點。當然,我們必須充分利用他們的優勢。 範例: concurrent 套件有很多多線程類,有自己的Concurrent集合。在多執行緒環境中處理資料時,ConcurrentHashMap 類別在安全性方面比標準 HashMap 具有優勢,但這是以效能較慢為代價的。在任何情況下都不是最佳選擇的實現將逐漸停止使用。 例如: Hashtable原本是打算成為線程安全的HashMap,但現在已經被遺忘並不再使用了,因為ConcurrentHashMap在多線程環境中工作時 甚至比Hashtable更好。93. 如何對元素集合進行排序?
首先要說的是,表示集合元素的類別必須實作Comparable接口,該接口由compareTo方法組成。或者您需要一個實作Comparator介面的類,包括其比較方法。這兩種方法都指示如何比較給定類型的物件。這在排序時至關重要,因為排序演算法需要了解使用什麼原理來比較元素。這主要是透過直接在要排序的類別中實作Comparable來完成的。使用比較器不太常見。假設您正在使用某個庫中的類,並且它沒有實作Comparable,但您需要對其物件的集合進行排序。由於您無法更改此類的程式碼(除非擴展它),因此您可以編寫Comparator的實作來指示如何比較該類別的物件。還有一個例子。如果您需要以不同的方式對相同類型的物件進行排序,那麼您可以編寫多個Comparator實作以在不同的情況下使用。通常,許多開箱即用的類別(例如String)已經實作了Comparable介面。這意味著您無需擔心如何比較這些類別。您可以繼續使用它們。 第一個也是最明顯的方法是使用TreeSet或TreeMap類別。這些類別根據類別元素實現的比較器按排序順序儲存元素。不要忘記TreeMap對鍵進行排序,而不是對值進行排序。如果您使用Comparator而不是Comparable,那麼您需要在建立集合時 將Comparator物件傳遞給集合的建構子:
TreeSet treeSet = new TreeSet(customComparator);
但是如果您有不同類型的集合怎麼辦?你如何排序?在這種情況下,Collections實用程式類別的第二種方法 — sort()方法 — 是適當的。此方法是靜態的,因此您所需要做的就是在前面新增類別的名稱,然後傳入要排序的清單。例如:
Collections.sort(someList);
如果您使用Comparator而不是Comparable 的實現,那麼您需要將其作為第二個參數傳遞:
Collections.sort(someList, customComparator);
此操作將變更傳遞清單中元素的內部順序:將使用比較器對清單進行排序。請注意,傳遞的清單必須是可變的,否則該方法將失敗並拋出UnsupportedOperationException。第三種選擇是使用Stream類別的排序方法,該方法對集合的元素進行排序。如果我們使用Comparable:
someList = someList.stream().sorted().collect(Collectors.toList());
如果我們使用比較器:
someList = someList.stream().sorted(customComparator).collect(Collectors.toList());
第四種方式是手動實作排序演算法,例如冒泡排序
或歸併排序
。
對象類別。equals() 和 hashCode()
94. 簡要描述Java中的Object類別。
在回顧的第二部分中,我們已經討論了 Object類別的方法。這裡我要提醒大家,Object類別是Java中每個類別的祖先。它有 11 個方法,依序被所有類別繼承。
95. Java中equals()和hashCode()的用途是什麼?
hashCode()是Object類別的一個方法,被所有類別繼承。它的工作是產生一個代表特定物件的數字。可以在HashMap中找到此方法的實際範例,其中對鍵物件調用該方法以獲取本地哈希碼,這將確定鍵值對將儲存在哪個儲存桶(內部數組的單元格)中。此外,該方法一般用在equals()方法中,作為其辨識物件的主要方式之一。 equals()是Object類別的一個方法,其作用是比較物件並確定它們是否相等。這個方法用在我們需要比較物件的任何地方,因為標準的==比較運算子不適合對象,因為它只比較物件參考。96. 請告訴我們 Java 中 equals() 和 hashCode() 之間的約定?
首先,我要說的是,為了讓equals()和hashCode()方法正常運作,必須正確重寫它們。他們的新實現必須遵循以下規則:- equals傳回true 的相同物件必須具有相同的雜湊碼。
- 具有相同哈希碼的物件不一定相等。
GO TO FULL VERSION