【问题标题】:What happens if return constant to hashcode and false to equals如果将常量返回到哈希码并且返回 false 到 equals 会发生什么
【发布时间】:2019-07-05 05:10:26
【问题描述】:

hashcode 或 hashmap 是如何工作的,如果我们重写 hashcode,它总是返回一个常量,而重写的 equals 方法返回 false,它如何在返回或删除时识别确切的对象? time bean 忘记了所有这些东西的性能,我的问题是它如何识别确切的对象,让我再解释一下,我有一个带有两个字段的 person 类,并且覆盖了始终返回 1 的哈希码和覆盖了返回 false 的 equals 方法,创建了 3 个对象,对象 1 - id 10 名称 AAAA,对象 2 - id 20,名称 BBB,对象 3 - id 30,名称 CCC,我已将所有三个对象添加到 hashSet,之后我删除了对象2、这里如何识别准确的对象(20、BBB)

【问题讨论】:

    标签: java hashmap equals hashset hashcode


    【解决方案1】:

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

    然而,始终返回 falseequals() 实现违反了 equals 的约定,并会导致许多类型的集合出现问题/令人惊讶的行为。

    来自JavaDocs of equals

    equals 方法在非空对象引用上实现等价关系:

    • 它是自反的:对于任何非空引用值 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,x.equals(y) 的多次调用始终返回 true 或始终返回 false,前提是没有修改对象上 equals 比较中使用的信息。李>
    • 对于任何非空引用值 x,x.equals(null) 应该返回 false。

    return false 实现打破了第一个要求。

    来自JavaDocs of hashcode

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

    正如 @Mensur Qulami 在 cmets 中指出的那样,如果您的实现使用与 == 的参考比较来优化节点搜索,它可能仍然可以与 HashMap 正常工作。

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

    ((k = first.key) == key || (key != null && key.equals(k))))

    所以这个实现在尝试equals() 之前检查引用相等性,但这不能保证。

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

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

    (这相当于ifequals的实现满足了上面的约定,所以OpenJDK做的优化是有效的)

    【讨论】:

    • 例如,明显的问题是Set 将无法区分对象以检测它们是否重复。
    • @Mensur Qulami,它的识别能力,我不知道它是怎么做的,我的问题只是,它是如何识别的
    • @user257918,不确定它是否可以识别2个相同的对象,但如果对象相同,它可以通过检查参考来检测。
    【解决方案2】:

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

    HashSet remove 最终调用HAshMap,removeNode 包含这个比较,看是否找到值。

                if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
    

    它比较hashCode,因为它是一个常数,所以总是相等的,然后首先使用==进行比较。如果 key 不是同一个对象(即== 为假),则只有equals 用于检查它们是否相等。

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

    【讨论】:

    • 虽然你可以说 hashmap 违反了 equals 方法,但实际上并没有。这是因为根据equals的javadoc,一个对象应该等于它自己
    猜你喜欢
    • 2019-10-07
    • 2014-03-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-07
    • 1970-01-01
    • 2015-07-10
    • 2015-06-22
    • 2015-05-09
    相关资源
    最近更新 更多