簡體   English   中英

Java:HashSet與HashMap

[英]Java : HashSet vs. HashMap

我有一個處理大量數據集的程序。 最好將對象存儲在散列實現的容器中,因為程序會繼續在容器中尋找對象。

第一個想法是使用HashMap,因為此容器的get和remove方法更適合我需要的用途。

但是,我發現使用HashMap消耗的內存相當大,這是一個主要問題,因此我認為切換到HashSet會更好,因為它僅對每個元素使用<E>而不是<K,V> ,但是當我看了我了解到的實現,它使用了底層的HashMap! 這意味着它不會節省任何內存!

所以這是我的問題:

  • 我所有的假設都正確嗎?
  • HashMap內存浪費嗎? 更具體地說,每個條目的開銷是多少?
  • HashSet和HashMap一樣浪費嗎?
  • 是否還有其他基於散列的容器,它們的內存消耗量將大大減少?

    更新

根據注釋中的要求,我將在程序上進行一些擴展,hashMap旨在容納一對其他對象,以及一些數字值-從它們計算得出的float值。 一路上,它會提取其中一些並輸入新對。 對於給定的一對,需要確保不握住該對或將其刪除。 可以使用對對象的float值或hashCode完成映射。

另外,當我說“巨大的數據集”時,我是在談論〜4 * 10 ^ 9個對象

這個站點上有關於Java集合性能的非常有用的技巧。

HashSet建立在HashMap< T, Object >頂部,其中value是單例“存在”對象。 這意味着the memory consumption of aHashSet is identical to HashMap :要存儲SIZE值,您需要32 * SIZE + 4 * CAPACITY個字節(加上值的大小)。 絕對不是對內存友好的集合。

THashSet可能是HashSet的最簡單替換集合-它實現了Set和Iterable,這意味着您應該只在初始化集時更新一個字母。

THashSet使用單個對象數組作為其值,因此它使用4 * CAPACITY字節進行存儲。 如您所見,與JDK HashSet相比,在相同的加載因子的情況下,您將節省 32 * SIZE字節,這是一個巨大的改進。

另外,我從這里拍攝的以下圖片可以幫助我們牢記某些事項,以選擇合適的收藏

在此處輸入圖片說明

我所有的假設都正確嗎?

您使用HashMap實現了HashSet是正確的,因此您不會通過使用HashSet來節省任何內存。

如果要創建包含大量元素的地圖,則應盡您所知,使用initialCapacity構造HashMap ,以防止重復進行哈希(從而導致內存顛簸)。

HashMap內存浪費嗎? 更具體地說,每個條目的開銷是多少?

不,這不是浪費。 開銷是一個基礎數組(大小由loadFactor修改),以及每個鍵值對的Entry對象。 除了存儲鍵和值外,條目對象還存儲指向插槽中下一個條目的指針(如果兩個或多個條目占用基礎數組中的同一插槽)。 默認的loadFactor為0.75可將基礎數組的大小保持為條目數的133%。

具體來說,每個條目的內存開銷為:

  • 入口對象對鍵的引用,
  • 入口對象對值的引用,
  • 條目對象對下一個條目的引用,
  • 以及基礎數組對條目的引用(除以負載系數)。

與基於散列的集合相比,要獲得更多的修剪是非常困難的。

HashSet和HashMap一樣浪費嗎?

使用HashSet而不是HashMap不會獲得任何內存效率。

是否還有其他基於散列的容器,它們的內存消耗量將大大減少?

如果您的鍵是基元(例如int ),則那里( 第三方庫中 )有自定義的MapSet實現,它們使用內存效率更高的數據結構。

確實,HashSet使用的內存與HashMap一樣多。 HasSet實現Set的兩者之間的區別,即,它不關心與某個鍵關聯的任何值,僅關心是否存在特定值。 HashMap與每個鍵的值的存儲/檢索(放置/獲取)有關。

雖然HashMap / HashSet將數據存儲在通常比元素數稍大的數組中,但由於負載因子為0.75,因此此保留並不是太大的問題。 這意味着,當元素數量達到基礎數組大小的75%時,HashMap將增長。

與大地圖相比,更大的問題是很多空地圖,因為HashMap的默認大小為16。這可以通過將初始容量設置為0來抵消。

但是,您也可以改用TreeMap,因為TreeMap是基於引用而不是數組的,所以您可能會浪費更多的空間,尤其是使用較大的地圖時,除了會損失一些速度。 TreeMap的主要優點在於,它會將鍵保持在有序狀態,因此,如果需要對它們進行排序,那是必須走的路。

此外,當您不能或不想對鍵類型的equalshashCode方法進行自定義實現時,由於編程原因,可以使用TreeMap。 您可以改用密鑰類型的比較器。 例如,要基於不區分大小寫的字符串創建映射/集合,請使用String.CASE_INSENSITIVE_ORDER作為TreeSet的比較器

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM