当前位置: 首页 > 知识库问答 >
问题:

如果未重写hashCode(),则HashSet允许重复项插入

勾俊
2023-03-14
class temp {
int id;

public int getId() {
  return id;
}

temp(int id) {
  this.id = id;
}

public void setId(int id) {
  this.id = id;
}

@Override
public boolean equals(Object obj) {
  if (this == obj)
      return true;
  if (obj == null)
      return false;
  if (getClass() != obj.getClass())
      return false;
  temp other = (temp) obj;
  if (id != other.id)
      return false;
  return true;
}
}

public class testClass {

    public static void main(String[] args) {
      temp t1 = new temp(1);
      temp t2 = new temp(1);
      System.out.println(t1.equals(t2));
      Set<temp> tempList = new HashSet<temp>(2);
      tempList.add(t1);
      tempList.add(t2);
      System.out.println(tempList);
}

该程序将两个元素都添加到Set中。起初我很震惊,因为在向set添加方法时,调用了equals方法。

但是后来我覆盖了hashCode方法:

@Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + id;
        return result;
    }

然后它没有添加。这是令人惊讶的,因为Set和add()方法的Javadoc表示,它在向集合中添加时只检查equals()。

这是add()的javadoc:

/**
     * Adds the specified element to this set if it is not already present.
     * More formally, adds the specified element <tt>e</tt> to this set if
     * this set contains no element <tt>e2</tt> such that
     * <tt>(e==null&nbsp;?&nbsp;e2==null&nbsp;:&nbsp;e.equals(e2))</tt>.
     * If this set already contains the element, the call leaves the set
     * unchanged and returns <tt>false</tt>.
     *
     * @param e element to be added to this set
     * @return <tt>true</tt> if this set did not already contain the specified
     * element
     */
    public boolean add(E e) {
      return map.put(e, PRESENT)==null;
    }

然后我意识到HashSet被实现为一个HashMap,在这个map中,对象的hashCode被用作键。因此,如果不重写哈希代码,则使用不同的键来处理它们。

这不应该在add()方法或HashSet的文档中吗?

共有3个答案

茅秦斩
2023-03-14

如果重写equals(),则还必须重写hashCode()。

对于equals()和hashCode()的行为有一些限制,它们在对象的文档中列举。特别是,equals()方法必须显示以下属性:

  • 对称性:对于a和b两个引用,a等于(b)当且仅当b等于(a)
  • 自反性:对于所有非空引用,a.equals(a)
  • 及物性:如果a.equals(b)和b.equals(c),那么a.equals(c)
  • 与hashCode()的一致性:两个相等的对象必须具有相同的hashCode()值

有关更多详细信息,请参见此。

鲁永福
2023-03-14

只需看一下文档:

请注意,每当重写hashCode方法时,通常都需要重写该方法,以便维护hashCode方法的一般约定,即相等的对象必须具有相等的哈希代码。

事实上,equals()和hashCode()是紧密联系在一起的。在与其中一个合作时,应始终考虑这两个方面,以避免这些一致性问题。

胡星汉
2023-03-14

它有点记录在案。请参阅java.lang.对象的留档,它在hashCode()上说:

如果两个对象根据equals(Object)方法相等,则在两个对象中的每一个上调用hashCode方法必须产生相同的整数结果。

此外,以下内容可在对象的文档中找到。等于(对象)方法

请注意,每当重写hashCode方法时,通常都需要重写该方法,以便维护hashCode方法的一般约定,即相等的对象必须具有相等的哈希代码。

换句话说,如果在类中使用instanceA。等于(instanceB)==true和instanceA。hashCode()!=istanceB。hashCode()您实际上违反了对象类的约定。

 类似资料:
  • 问题内容: 该程序将两个元素都添加到集合中。起初我很震惊,因为在添加设置方法时,调用了equals方法。 但是后来我覆盖了hashCode方法: 然后没有添加。这是令人惊讶的,因为Set和add()方法的Javadoc说它在添加到Set中时仅检查equals()。 这是add()的javadoc: 然后我意识到HashSet被实现为HashMap,并且在地图中,对象的hashCode用作键。因此,

  • 问题内容: 我似乎无法使实例正常工作。我使用的代码如下: 子类 该代码输出 问题答案: 您需要覆盖。而不是这样做,您实现了一个带有signature 的方法。因此,您使用的是为相等性测试定义的默认方法。 默认实现基于对象标识,因此,该集合“允许”您添加两个在语义上相等的不同对象。

  • 我正在检查< code>HashSet的< code>add方法。有人提到 如果该集合已经包含元素,则调用保持集合不变,并返回false。 但是方法在内部保存中的值 的方法声明 将指定值与该映射中的指定键相关联。如果映射先前包含该键的映射,则旧值将被替换。 那么,如果 的 方法替换了旧值,那么 方法如何在元素重复的情况下保持集合不变?

  • } ========================================================================================== 我希望HashSet调用equal方法,因为重写了hashCode。在equals compare之后,我想删除我要传递到hashSet的集合中的重复项。 在控制台中,它将我打印出来,为true(因为在equals

  • 问题内容: 假设您有一个类,并创建了一个HashSet来存储此类的实例。如果尝试添加相等的实例,则集合中仅保留一个实例,这很好。 但是,如果HashSet中有两个不同的实例,并采用一个实例并使其与另一个实例完全相同(通过复制字段),则HashSet将包含两个重复的实例。 这是演示此代码的代码: 上面代码的输出: 有没有一种方法可以强制HashSet验证其内容,以便删除在上述情况下创建的可能重复条目

  • 本文向大家介绍插入Delete GetRandom O(1)-C ++中允许重复,包括了插入Delete GetRandom O(1)-C ++中允许重复的使用技巧和注意事项,需要的朋友参考一下 假设我们要创建一个支持某些操作的数据结构,这些操作必须在O(1)的时间内执行。所以让这些操作像- insert(x):将x插入集合 remove(x):从集合中删除x getRandom():这将找到该集