如果将常数返回给哈希码而将false返回等于

时间:2019-07-05 05:10:26

标签: java hashmap equals hashset hashcode

哈希码或哈希图是如何工作的,如果我们重写总是返回常量的哈希码,而覆盖的equals方法则返回false,那么它如何在返回或删除时识别出确切的对象? time bean忘记了所有这些性能,我的问题是它如何识别确切的对象,让我进一步解释,我有一个包含两个字段的人员类,并且覆盖了返回始终为1的哈希码和覆盖了返回false的equals方法,创建了3个对象,对象1-id 10名称AAAA,对象2-id 20,名称BBB,对象3-id 30,名称CCC,我将所有三个对象添加到hashSet中,然后删除了对象2,这里是如何识别确切的对象(20,BBB)

2 个答案:

答案 0 :(得分:2)

使用HashMap / HashSet或其他使用它来优化比较/搜索的代码时,常量哈希码是有效的,并且“仅”是性能问题。

一个始终返回equals()的{​​{1}}实现会破坏平等契约,并会导致许多类型的集合出现问题/令人惊讶的行为。

JavaDocs of equals

  

equals方法对非null对象引用实现等效关系:

     
      
  • 这是自反的:对于任何非空参考值x,x.equals(x)应该返回true。
  •   
  • 这是对称的:对于x和y的任何非空参考值,当且仅当y.equals(x)返回true时,x.equals(y)才应返回true。
  •   
  • 是可传递的:对于x,y和z的任何非空引用值,如果x.equals(y)返回true,而y.equals(z)返回true,则x.equals(z)应该返回true 。
  •   
  • 这是一致的:对于任何非空参考值x和y,只要未修改对象的equals比较中使用的信息,对x.equals(y)的多次调用将始终返回true或始终返回false。
  •   
  • 对于任何非空参考值x,x.equals(null)应该返回false。
  •   

false实现违反了第一个要求。

来自JavaDocs of hashcode

  
      
  • 如果两个对象根据equals(java.lang.Object)方法不相等,则不需要在两个对象中的每个对象上调用hashCode方法必须产生不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同的整数结果可能会提高哈希表的性能。
  •   

正如@Mensur Qulami在评论中指出的那样,如果您的实现使用与return false的引用比较来优化对节点的搜索,它似乎仍然可以与HashMap一起正常工作。

来自OpenJDK 12 HashMap.getNode(int hash, Object key)

  

==

因此,此实现在尝试((k = first.key) == key || (key != null && key.equals(k))))之前检查引用是否相等,但这不能保证。

JavaDocs for HashMap.get严格按照equals()的定义

  

更正式地说,如果此映射包含从键k到值v的映射,使得equals(),则此方法返回(key==null ? k==null : key.equals(k));否则返回v

(这等效于 if null的实现满足上述约定,因此OpenJDK进行的优化有效)

答案 1 :(得分:1)

即使equals返回false,它仍然可以删除对象,因为==仍然返回true(==比较实际的对象引用,不受{{ 1}}实施)。

HashSet remove最终调用HAshMap,removeNode包含此比较以查看是否找到该值。

equals

它比较hashCode,因为它是一个常量,所以始终相等,然后首先使用 if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) 进行比较。如果密钥不是同一对象(即==为假),则仅使用==来检查它们是否相等。

如果您要创建一个具有相同值的新对象,则永远无法使用它从集合中删除该值,但是当您使用同一对象时,由于equals仍然可以使用