Java equals 和 hashCode 的这几个问题可以说明白吗? (2)

很显然,按照集合 Set 和 Map 加入元素的标准来看,student1 和 student2 是两个对象,因为在调用他们的 put (Set add 方法的背后也是 HashMap 的 put)方法时, 会先判断 hash 值是否相等,这个小伙伴们打开 JDK 自行查看吧

所以我们继续重写 Student 类的 hashCode 方法:

@Override public int hashCode() { return Objects.hash(name, age); }

重新运行上面的测试,查看结果:

student1.equals(student2)的结果是:true Student Set 集合长度是:1 Student Map 集合长度是:1

得到我们预期的结果,这也就是为什么通常我们重写 equals 方法为什么最好也重写 hashCode 方法的原因

如果你在使用 Lombok,不知道你是否注意到 Lombok 只有一个 @EqualsAndHashCode 注解,而没有拆分成 @Equals 和 @HashCode 两个注解,想了解更多 Lombok 的内容,也可以查看我之前写的文章 Lomok 使用详解

另外通过 IDE 快捷键生成重写方法时,你也会看到这两个方法放在一起,而不是像 getter 和 setter 那样分开

Java equals 和 hashCode 的这几个问题可以说明白吗?

以上两点都是隐形的规范约束,希望大家也严格遵守这个规范,以防带来不必要的麻烦,记忆的方式有多样,如果记不住这个文字约束,脑海中记住上面的图你也就懂了

5. 重写 hashCode 为什么总有 31 这个数字?

细心的朋友可能注意到,我上面重写 hashCode的方法很简答, 就是用了 Objects.hash 方法,进去查看里面的方法:

public static int hashCode(Object a[]) { if (a == null) return 0; int result = 1; for (Object element : a) result = 31 * result + (element == null ? 0 : element.hashCode()); return result; }

这里通过 31 来计算对象 hash 值

在 如何妙用 Spring 数据绑定? 文章末尾提到的在 HandlerMethodArgumentResolverComposite 类中有这样一个成员变量:

private final Map<MethodParameter, HandlerMethodArgumentResolver> argumentResolverCache = new ConcurrentHashMap<MethodParameter, HandlerMethodArgumentResolver>(256);

Map 的 key 是 MethodParameter ,根据我们上面的分析,这个类一定也会重写 equals 和 hashCode 方法,进去查看发现,hashCode 的计算也用到了 31 这个数字

@Override public boolean equals(Object other) { if (this == other) { return true; } if (!(other instanceof MethodParameter)) { return false; } MethodParameter otherParam = (MethodParameter) other; return (this.parameterIndex == otherParam.parameterIndex && getMember().equals(otherParam.getMember())); } @Override public int hashCode() { return (getMember().hashCode() * 31 + this.parameterIndex); }

为什么计算 hash 值要用到 31 这个数字呢?我在网上看到一篇不错的文章,分享给大家,作为科普,可以简单查看一下:
String hashCode 方法为什么选择数字31作为乘子

总结

如果还对equals 和 hashCode 关系及约束含混,我们只需要按照上述步骤逐步回忆即可,更好的是直接查看 JDK 源码;另外拿出实际的例子来反推验证是非常好的办法。如果你还有相关疑问,也可以留言探讨.

灵魂追问

Thread 类就没有重写 equals 方法,你还知道哪些情况没必要重写 equals 方法吗?

从上面 HandlerMethodArgumentResolverComposite 类中定义的 Map 成员变量,你注意到哪些知识点,比如 final,ConcurrentHashMap,初识容量,为什么要这样写?你能解释出原因吗?

欢迎持续关注公众号:「日拱一兵」

前沿 Java 技术干货分享

高效工具汇总 | 回复「工具」

面试问题分析与解答

技术资料领取 | 回复「资料」

以读侦探小说思维轻松趣味学习 Java 技术栈相关知识,本着将复杂问题简单化,抽象问题具体化和图形化原则逐步分解技术问题,技术持续更新,请持续关注......

Java equals 和 hashCode 的这几个问题可以说明白吗?

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzpwpd.html