如果不覆盖hashCode(),HashSet允许重复项目插入

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 tempList = new HashSet(2); tempList.add(t1); tempList.add(t2); System.out.println(tempList); } 

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

但后来我覆盖了hashCode方法:

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

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

这是add()的javadoc:

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

然后我意识到HashSet是作为HashMap实现的,在地图中,对象的hashCode用作键。 因此,如果你不重写hashCode,它会使用不同的键来处理它们。

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

有点记录。 请参阅java.lang.Object的文档,它在hashCode()

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

此外,在Object.equals(Object)方法的文档中可以找到以下内容:

请注意,通常需要在重写此方法时覆盖hashCode方法,以便维护hashCode方法的常规协定,该方法声明相等的对象必须具有相等的哈希代码

换句话说,如果你的类在instanceA.equals(instanceB) == trueinstanceA.hashCode() != istanceB.hashCode()你实际上违反了Object类的契约。

只需看看equals()文档:

请注意,通常需要在重写此方法时覆盖hashCode方法,以便维护hashCode方法的常规协定,该方法声明相等的对象必须具有相等的哈希代码

事实是equals()hashCode()是强关联的。 在处理其中一个时,应始终考虑两者以避免这些一致性问题。

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

对equals()和hashCode()的行为有一些限制,这些限制在Object的文档中列举。 特别是,equals()方法必须具有以下属性:

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

有关详细信息,请参阅此

他们(javadoc人)可能已经预先假设他们说(在HashSetadd()方法的文档)

 (e==null ? e2==null : e.equals(e2)) 

hashCode()对于它们两者本质上是相等的。