HashSet允许具有相同HashCode的多个项目

时间:2019-06-03 17:41:56

标签: java hashset

我的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

2 个答案:

答案 0 :(得分:4)

集合基于equals方法(1)防止重复。来自javadoc(我强调):

  

不包含重复元素的集合。更正式地说,集合包含没有一对元素e1和e2,使得e1.equals(e2),最多不包含一个空元素。

如果元素根据其哈希码应相等,则相应地实现equals方法(例如,仅比较调用hashCode的结果)。请注意,这可能不是最好的主意,因为您的equals方法当前会评估更多属性。

(1):至少您当前使用的HashSet

答案 1 :(得分:0)

您刚刚观察到的是哈希码冲突。因为哈希码函数将值从较大的集合(例如,所有可能的String,有无数个)映射到较小的集合(例如,所有可能的int,只有2 ^ 32个不同的值),会是碰撞。

这就是为什么利用哈希的数据结构始终处理哈希冲突的原因,例如通过实现Hash Tables wiki, Collision resolution section。您可以查看https://pastebin.com/4UQDjSWa来更好地理解问题:

  

散列大量可能密钥的随机子集时,散列冲突实际上是不可避免的。例如,如果将2450个密钥散列到一百万个存储桶中,即使具有完全均匀的随机分布,则根据生日问题,至少有两个密钥散列到同一插槽的机率大约为95%。