相等原则:equals()和hashCode()

在编程语言的宇宙中有一世界叫做 JavaJava 中有一个超级老祖,叫做 Object, 他是所有类的共同的父类,所有对象均隐性继承了此类。 Object 有两个方法,equals()hashCode(); 这两个方法也是隐性的传承给了所有的对象。

一、equals()

1.1 equals()简介

equals()方法是Java中的一个方法,用于比较两个对象是否相等。它是在Object类中定义的,因此所有的Java类都继承了这个方法。

默认情况下,equals()方法比较两个对象的引用是否相等,也就是它们是否指向了内存中的同一个对象。这是因为Object类的equals()方法实现如下:

java 复制代码
public boolean equals(Object obj) {
    return (this == obj);
}

然而,在实际开发中,我们通常需要根据对象的属性来确定它们是否相等,而不仅仅是比较引用。这就需要我们在自定义类中重写equals()方法,以便根据业务逻辑来定义相等性比较。

1.2 equals()重写(自定义类对象内容是否相等)

通过重写equals()方法,我们可以根据自定义的相等性逻辑来比较对象,而不仅仅是比较引用。这样可以提高对象比较的灵活性和准确性。在使用集合类、比较对象等场景时,正确实现equals()方法非常重要。

在重写equals()方法时,我们通常需要考虑以下几个方面:

graph LR A(重写equals方法遵循原则) B(检查传入的参数是否为null 如果是null 则直接返回false) C(检查传入的参数是否为当前类的实例 如果不是 则返回false) D(将传入的参数转换为当前类的类型 并比较对象的属性是否相等) E(对于引用类型的属性 可以使用它们的equals方法进行比较) F(对于基本类型的属性 可以使用 == 运算符进行比较) A ---> B A ---> C A ---> D A ---> E A ---> F style B fill:#FFC0CB,stroke:#FFC0CB,stroke-width:2px style C fill:#FFA07A,stroke:#FFA07A,stroke-width:2px style D fill:#FFFFE0,stroke:#FFFFE0,stroke-width:2px style E fill:#98FB98,stroke:#98FB98,stroke-width:2px style F fill:#B2FFFF,stroke:#B2FFFF,stroke-width:2px

下面是一个示例,演示了如何重写equals()方法:

java 复制代码
public class Person {
    private String name;
    private int age;

    // 构造函数、getter和setter方法等省略

    @Override
    public boolean equals(Object obj) {
        // 检查传入的参数是否为null
        if (obj == null) {
            return false;
        }

        // 检查传入的参数是否为当前类的实例
        if (getClass() != obj.getClass()) {
            return false;
        }

        // 将传入的参数转换为当前类的类型
        Person other = (Person) obj;

        // 比较对象的属性是否相等
        return name.equals(other.name) && age == other.age;
    }
}

二、hashCode()

2.1 hashCode()简介

hashCode()方法是Java中的一个方法,用于返回对象的哈希码(整数值)。它是在 Object 类中定义的,因此所有的 Java 类都继承了这个方法。

哈希码是根据对象的属性计算得出的一个整数值。它通常用于在哈希表等数据结构中进行对象的存储和查找。哈希表是一种根据键值对存储和检索数据的数据结构,它通过将键转换为哈希码来确定存储位置,从而实现快速的数据访问。

Java 中,哈希表的实现类(如 HashMapHashSet 等)使用了对象的哈希码来决定对象在表中的存储位置。因此,重写equals()方法时通常也需要重写 hashCode()方法,以确保相等的对象具有相等的哈希码

以下是hashCode()方法的默认实现,来自Object类:

java 复制代码
public int hashCode() {
    return super.hashCode();
}

2.2 hashCode()重写(自定义类对象内容是否相等)

默认情况下,hashCode()方法返回的是对象的内部存储地址的哈希码,即对象的标识哈希码。然而,这种默认实现通常不满足我们对相等性的要求。

在重写hashCode()方法时,我们通常需要遵循以下几个原则:

graph LR A(重写hashCode方法遵循原则) B(相等的对象必须具有相等的哈希码) C(尽量使不相等的对象具有不同的哈希码 以提高哈希表的性能) D(哈希码的计算应基于对象的属性) A ---> B A ---> C A ---> D style B fill:#FFC0CB,stroke:#FFC0CB,stroke-width:2px style C fill:#FFA07A,stroke:#FFA07A,stroke-width:2px style D fill:#FFFFE0,stroke:#FFFFE0,stroke-width:2px
  1. 相等的对象必须具有相等的哈希码。这意味着如果equals()方法返回true,则两个对象的hashCode()方法应返回相同的值。

  2. 尽量使不相等的对象具有不同的哈希码,以提高哈希表的性能。尽量避免不相等的对象具有相同的哈希码,这会导致哈希冲突,影响查找效率。

  3. 哈希码的计算应基于对象的属性。通常可以使用对象的属性值来计算哈希码,例如字符串的哈希码可以使用其字符序列的哈希码计算得出。

下面是一个示例,演示了如何重写hashCode()方法:

java 复制代码
public class Person {

    private String name;
    private int age;

    // 构造函数、getter和setter方法等省略

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

注意 :重写hashCode()方法时,需要确保与equals()方法的逻辑一致。这样,当两个对象根据equals()方法比较相等时,它们的哈希码也应该相等。

正确实现hashCode()方法可以提高哈希表等数据结构的性能,并确保对象能够在集合类中正确存储和检索。

三、思考:两个对象的hashCode()相同,则 equals()是否也一定为true?

结论 :两个对象 equals() 相等,则它们的 hashCode() 必须相等,如果两个对象的hashCode()相同,则 equals()不一定为 true

3.1 扩展知识

Java中,关于hashCode()方法有一些常规协定和约定俗成的规则。这些规则有助于确保正确实现hashCode()方法,并使其在哈希表等数据结构中正常工作。

以下是hashCode()方法的常规协定 (非强制规定):

  • 一致性 :在对象没有发生属性变化的情况下,多次调用hashCode()方法应该始终返回相同的值。只有当对象的属性发生变化时,hashCode()方法的返回值才可以改变。

  • 相等性一致性 :如果两个对象根据equals()方法比较相等,那么它们的hashCode()方法必须返回相同的值。即使两个对象的属性发生变化,只要它们仍然相等,它们的哈希码必须保持一致。

  • 哈希码分布均匀性:不相等的对象应该具有不同的哈希码,以减少哈希冲突的可能性,提高哈希表等数据结构的性能。尽量使哈希码在整个可能的范围内均匀分布,以避免热点区域的聚集。

  • 性能考虑hashCode()方法的计算应该高效,尽量避免复杂的操作和耗时的计算。由于哈希码通常在哈希表等数据结构中频繁使用,性能较低的hashCode()方法可能会影响整体性能。

四、总结

Java中,equals()hashCode()方法是用于对象相等性比较和哈希表存储的重要方法。

这两个方法在一起使用,可以保证对象在哈希表等数据结构中正确存储和检索,并确保对象的相等性比较得到正确的结果。它们在集合类(如HashMapHashSet)中广泛使用,以提供高效的元素存储和查找功能。

希望本文对您有所帮助。如果有任何错误或建议,请随时指正和提出。

同时,如果您觉得这篇文章有价值,请考虑点赞和收藏。这将激励我进一步改进和创作更多有用的内容。

感谢您的支持和理解!

相关推荐
并不会37 分钟前
常见 CSS 选择器用法
前端·css·学习·html·前端开发·css选择器
衣乌安、40 分钟前
【CSS】居中样式
前端·css·css3
兔老大的胡萝卜41 分钟前
ppk谈JavaScript,悟透JavaScript,精通CSS高级Web,JavaScript DOM编程艺术,高性能JavaScript pdf
前端·javascript
低代码布道师43 分钟前
CSS的三个重点
前端·css
耶啵奶膘2 小时前
uniapp-是否删除
linux·前端·uni-app
NiNg_1_2343 小时前
SpringBoot整合SpringSecurity实现密码加密解密、登录认证退出功能
java·spring boot·后端
王哈哈^_^4 小时前
【数据集】【YOLO】【目标检测】交通事故识别数据集 8939 张,YOLO道路事故目标检测实战训练教程!
前端·人工智能·深度学习·yolo·目标检测·计算机视觉·pyqt
Chrikk4 小时前
Go-性能调优实战案例
开发语言·后端·golang
幼儿园老大*4 小时前
Go的环境搭建以及GoLand安装教程
开发语言·经验分享·后端·golang·go
canyuemanyue4 小时前
go语言连续监控事件并回调处理
开发语言·后端·golang