我有一个HashSet<Obj>
包含一个项目。尝试添加到集合中的新项目与现有项目.equals()
相同。为了确认newElement
实际上是相同的,我有一些调试打印循环通过我的HashSet
并打印每个项目:
does current item .equals(newElement)
。
这确认集合中已有.equals()
个对象。
这是有趣的开始,如果我打电话给add(newElement)
我希望它不会添加,或至少覆盖已经在集合中的内容。该组在添加后应该只有1个唯一项。就我而言,它有2个!
为了帮助弄清楚为什么add()
正在以这种方式工作,我运行了Set.contains(newElement)
,它应该返回true,但在我的情况下它返回false。这就是我的add()
按照它的方式工作的原因。
集合中的某个项目可能为.equals(newElement)
但Set.contains(newElement)
的任何原因可能会返回false?我检查了我的.equals()
,它似乎按照我的预期工作,打印出来的对象显示了.equals()
确认的内容。我想也许HashSet
如何处理add
和contains
,但是从Java文档中检查(o==null ? e==null : o.equals(e))
。
我也覆盖了hashCode()
,我在打印中使用的值作为调试的一部分,显示了相同的逻辑项。
答案 0 :(得分:3)
集合中的项目可能是.equals(newElement)但Set.contains(newElement)可能返回false的原因是什么?
是的 - 您需要实施hashCode()
以及等号,需要检查与equals()
完全相同的字段。你说哈希码只是大致相等,这没有多大意义。如果hashCode()
为两个不同的对象返回不同的结果(默认情况下,如果你没有覆盖它),那么HashSet
将假定它们是唯一的(即使equals()
返回真。)
如果hashCode()
为两个对象返回相同的值,并且equals()
返回true(在两个对象上对称),那么这将确保您不能在HashSet中同时拥有这两个对象。这条规则没有(明智的)例外,所以如果你认为hashCode()
和equals()
的行为都是正确且一致的,那么你的逻辑肯定存在缺陷。
答案 1 :(得分:0)
Equals和hashCode方法有一个特定的合同:
1.如果元素彼此相等,即equals返回true,则这些对象的hashCode值必须匹配。
2.如果对象的hashCode值相同,那么这并不意味着它们的等于将返回true,即。物体不必彼此相等,即碰撞是可能的。
现在分别考虑每个案例:
1.Equals和hashCode没有被覆盖,这意味着只有当链接相等时,equals才会返回true,并且hashCode可以相等或不相等。无论hashCode的值如何,大小都是2。
2.equals和hashCode被重新定义,然后我们将具有相同的哈希值,我们将得到相同的表格单元格,equals将确定列表中的对象已经存在,因此大小将等于1。
3.equals没有重新定义,hashCode被覆盖。在这种情况下,单元格索引将是相同的,但在列表中找不到相同的元素,因此大小将等于2。
4.equals被覆盖,hashCode未定义。这取决于如何在Object类中生成hashCode的值。如果值相同,则列表将相同,因此,表中的元素数将为1.如果不同,搜索将在不同的列表中进行,并且将找不到重复项,然后大小将等于2.
类似地,执行remove,contains操作。
有关HashSet / contains的示例:
class Dog{
String color;
public Dog(String s){
color = s;
}
}
public class SetAndHashCode {
public static void main(String[] args) {
HashSet<Dog> dogSet = new HashSet<Dog>();
dogSet.add(new Dog("white"));
dogSet.add(new Dog("white"));
System.out.println("We have " + dogSet.size() + " white dogs!");
if(dogSet.contains(new Dog("white"))){
System.out.println("We have a white dog!");
}else{
System.out.println("No white dog!");
}
}
}