Object.hashCode() 详解

在Java编程中,hashCode方法是一个常见而重要的概念。它通常用于哈希表、集合以及一些需要高效检索数据的数据结构中。然而,对于许多开发者来说,hashCode方法可能是一个容易被忽略或者被简单实现的部分。在本文中,我们将深入探讨Java中hashCode的一些思考,以便更好地理解其背后的原理和影响。

hashcode.jpg

hashCode的简介

hashCode 返回的 "散列码" 是指通过哈希算法生成的一个整数,用于标识对象的唯一性。在Java中,hashCode方法被设计用来支持基于哈希的集合类,如HashMap、HashSet等,以及其他需要快速检索数据的数据结构。

hashCode的意义

  • 快速检索

散列码的主要作用是提高数据结构的检索效率。在哈希表中,通过散列码可以迅速定位到存储数据的位置,而不需要遍历整个数据集。这对于大规模数据集的快速检索非常重要,能够使得检索操作的时间复杂度接近常数级别。

  • 哈希集合性能

在使用哈希集合(如HashSet)时,散列码决定了元素在集合中的存储位置。如果不同的对象具有相同的散列码,就会发生哈希冲突,需要通过其他手段解决,如链地址法或开放寻址法。因此,好的散列码设计能够最小化哈希冲突,提高哈希集合的性能。

  • equals方法辅助

hashCode方法与equals方法是相关联的。在Java中,根据对象相等性的定义,如果两个对象相等(equals方法返回true),那么它们的散列码应该相等。这一关系有助于在哈希集合中正确地比较和存储对象。

  • 分布均匀

散列码的设计应尽量使得不同的对象生成不同的散列码,以减少哈希冲突的可能性。这需要考虑到对象的各个属性,确保它们都对最终的散列码有贡献,避免简单地依赖于某一个属性。

重写 hashCode 方法

为什么要重写 hashCode 方法

Object类中提供的默认实现是与当前线程有关的随机数和其他三个固定值进行xorshift运算后的结果数。这种默认实现在实际应用中可能并不总是满足需要,特别是当我们需要基于对象的内容来计算哈希码时。

源码如下:

csharp 复制代码
public native int hashCode();

如何重写hashCode方法

在自定义类中,如果希望基于对象的内容生成哈希码,通常需要重写hashCode()方法。为了简化哈希码的计算,我们可以使用Objects工具类,提供了hash方法,可以接受多个参数,并根据它们生成一个合并后的哈希码。

示例如下:

typescript 复制代码
@Data
public class UrlEntity {
    private Integer id;
    private String url;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        UrlEntity entity = (UrlEntity) o;
        return Objects.equals(id, entity.id) && Objects.equals(url, entity.url);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, url);
    }

哈希冲突

由于哈希码是一个有限位数的整数,不同的对象可能生成相同的哈希码,这就是哈希冲突。为了最小化哈希冲突的概率,好的哈希码应该能够均匀分布。在实际应用中,可以通过一些技巧和算法来提高哈希码的质量,减少冲突的可能性。

比如如下代码:

typescript 复制代码
public static void main(String[] args) {
    String str1 = "3C";
    String str2 = "2b";
    System.out.println("字符串"+str1+"的hashCode值为:"+str1.hashCode());
    System.out.println("字符串"+str2+"的hashCode值为:"+str2.hashCode());
}

运行结果为:

字符串3C的hashCode值为:1648
字符串2b的hashCode值为:1648

不同的对象,却拥有了相同的 hashCode值, 这就是哈希冲突。

为什么重写equals方法时一定要重写hashCode方法

在Java中,equals 方法和 hashCode 方法之间存在一种协定,这个协定规定了如果两个对象根据 equals 方法被认为相等,那么它们的 hashCode 值必须相等。反之亦然,如果两个对象的 hashCode 值相等,它们不一定要相等。

这一规定的原因在于,在使用基于散列的集合类(例如 HashMap、HashSet 等)时,对象的 hashCode 值通常用于确定对象在内部存储结构中的位置。当你在集合中使用对象时,集合会首先检查对象的 hashCode 值,然后再使用 equals 方法来确保这个位置上没有相等的对象。

如果你重写了 equals 方法但没有重写 hashCode 方法,那么可能会导致违反这个协定,即相等的对象具有不同的 hashCode 值。这样的情况会导致在使用散列集合时出现问题,因为相等的对象应该被视为相等,它们应该在集合中占据相同的位置。

总结

在Java中,Object.hashCode()方法在处理集合类和对象比较时发挥着关键作用。了解其原理以及如何正确重写这个方法对于编写高效、正确的代码至关重要。通过理解哈希码的生成方式,我们可以更好地利用Java的集合类,并确保我们的自定义类在使用这些类时能够正确地工作。

相关推荐
Estar.Lee6 分钟前
查手机号归属地免费API接口教程
android·网络·后端·网络协议·tcp/ip·oneapi
2401_857610032 小时前
SpringBoot社团管理:安全与维护
spring boot·后端·安全
凌冰_2 小时前
IDEA2023 SpringBoot整合MyBatis(三)
spring boot·后端·mybatis
码农飞飞2 小时前
深入理解Rust的模式匹配
开发语言·后端·rust·模式匹配·解构·结构体和枚举
一个小坑货2 小时前
Rust 的简介
开发语言·后端·rust
monkey_meng3 小时前
【遵守孤儿规则的External trait pattern】
开发语言·后端·rust
Estar.Lee3 小时前
时间操作[计算时间差]免费API接口教程
android·网络·后端·网络协议·tcp/ip
新知图书4 小时前
Rust编程与项目实战-模块std::thread(之一)
开发语言·后端·rust
盛夏绽放4 小时前
Node.js 和 Socket.IO 实现实时通信
前端·后端·websocket·node.js
Ares-Wang4 小时前
Asp.net Core Hosted Service(托管服务) Timer (定时任务)
后端·asp.net