簡體   English   中英

HashSet允許具有相同HashCode的多個項目

[英]HashSet allows multiple items with same HashCode

我的HashSet包含多個具有相同HashCode的“ AccessRequests”。 我只希望有一個實例。 我不認為具有相同HashCode的項目可以顯示在HashSet中。 我在這里做錯了什么?

更新:基於這樣的假設:HashSet僅保留一個與列表中的另一個不相等的項目,並且可能我的equals / hash方法需要簡化,因此我更新了問題。 我的HashSet中仍然有多個項目等於Equals。

以下是來自“ AccessRequest”的HashCode和Equals方法

更新:我更新了我的哈希值,等於只具有我需要“等於”的必要字段

    @Override
public int hashCode() {
    int hash = 5;
    hash = 79 * hash + Objects.hashCode(this.targets);
    hash = 79 * hash + Objects.hashCode(this.sources);
    hash = 79 * hash + Objects.hashCode(this.destinations);
    hash = 79 * hash + Objects.hashCode(this.services);
    hash = 79 * hash + Objects.hashCode(this.action);
    return hash;
}

@Override
public boolean equals(Object obj) {
    if (this == obj) {
        return true;
    }
    if (obj == null) {
        return false;
    }
    if (getClass() != obj.getClass()) {
        return false;
    }
    final AccessRequest other = (AccessRequest) obj;
    if (!Objects.equals(this.action, other.action)) {
        return false;
    }
    if (!Objects.equals(this.targets, other.targets)) {
        return false;
    }
    if (!Objects.equals(this.sources, other.sources)) {
        return false;
    }
    if (!Objects.equals(this.destinations, other.destinations)) {
        return false;
    }
    if (!Objects.equals(this.services, other.services)) {
        return false;
    }
    return true;
}

創建AccessRequest之后,我將它們轉儲到HashSet中並進行迭代:我的HashSet定義如下:

 Set<AccessRequest> ars = new HashSet();

       ArrayList<AccessRequest> arsAsList = new ArrayList(ars);
        for(int position=0;position<arsAsList.size();position++){
            AccessRequest fixedAR = arsAsList.get(position);
            ArrayList<AccessRequest> comparToList = new ArrayList(ars);
            for(int cPosition=0;cPosition<comparToList.size();cPosition++){
                AccessRequest nextAR = comparToList.get(cPosition);
                if(fixedAR.equals(nextAR)){
                    System.out.println("position= "+position+"  cPosition "+cPosition);
                }
            }
            System.out.println("\n Next AR");
        }

以下是輸出:

position= 0  cPosition 0
position= 0  cPosition 5
position= 0  cPosition 6
position= 0  cPosition 14
position= 0  cPosition 24
position= 0  cPosition 32
position= 0  cPosition 39
position= 0  cPosition 40
position= 0  cPosition 43
position= 0  cPosition 77
position= 0  cPosition 96
position= 0  cPosition 97
position= 0  cPosition 99
position= 0  cPosition 109
position= 0  cPosition 111
position= 0  cPosition 115
position= 0  cPosition 173
position= 0  cPosition 182
position= 0  cPosition 187

集合基於equals方法(1)防止重復。 javadoc (我強調):

不包含重復元素的集合。 更正式地講,集合不包含元素e1和e2對,例如e1.equals(e2) ,最多不包含一個null元素。

如果您的元素根據其哈希碼應相等,則相應地實現equals方法(例如,僅比較調用hashCode的結果)。 請注意,這可能不是最好的主意,因為equals方法當前會評估更多屬性。

(1):至少是您當前正在使用的HashSet

您剛剛觀察到的是哈希碼沖突。 因為哈希碼函數將值從較大的集合(例如,所有可能的String ,有無限數量)映射到較小的集合(例如,所有可能的int ,僅2 ^ 32個不同的值),所以總是會發生沖突。

這就是為什么利用哈希的數據結構始終處理哈希沖突的原因,例如通過實現Open Addressing 您可以查看Hash Tables Wiki的“沖突解決”部分,以更好地了解問題:

當散列大量可能密鑰的隨機子集時,散列沖突實際上是不可避免的。 例如,如果將2450個密鑰散列到一百萬個存儲桶中,即使具有完全均勻的隨機分布,則根據生日問題,至少有兩個密鑰散列到同一插槽的機率大約為95%。

暫無
暫無

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

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