马士兵java架构师

您现在的位置是:架构师问答 >

架构师问答

Java中equals()和hashCode()的联系?

2023-11-13 16:30:49架构师问答 本文浏览次数:1 百度已收录

本 文 目 录

equals()hashCode()两个方法在Java中都具有重要地位。它们之间有着微妙的联系,并且对于Java集合框架和对象比较来说,二者都至关重要。

一、为什么需要同时理解equals()和hashCode()?

在Java的集合框架中,比如HashSet、HashMap等,元素的存储和检索都依赖于hashCode()方法。而当我们想要判断两个对象是否相等时,我们会使用equals()方法。如果两个对象相等(即equals()返回true),那么它们的hashCode()必须返回相同的值。否则,集合的行为将出现异常。

二、equals()和hashCode()的联系

  • 对称性:如果两个对象相等(即equals(Object obj)返回true),那么它们的哈希码(由hashCode()返回)必须相等。
  • 一致性:如果两个对象在equals()中被视为相等,那么它们必须具有相同的哈希码,无论它们被调用多少次。

三、代码案例

下面是一个简单的例子,用于说明如果equals()hashCode()不一致,将会出现的问题。

public class Test {
    private String name;

    public Test(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Test test = (Test) o;
        return Objects.equals(name, test.name);
    }

    // 故意使得两个equals的对象具有不同的hashcode
    @Override
    public int hashCode() {
        return name.length();
    }
}

public static void main(String[] args) {
    Test t1 = new Test("test1");
    Test t2 = new Test("test2");
    Set<Test> set = new HashSet<>();
    set.add(t1);
    set.add(t2);  // 这里假设我们期望t1和t2被视为相等,并从集合中删除一个
    System.out.println(set.size());  // 输出结果将是2,而不是我们期望的1
}

Test 类定义

这个代码案例主要涉及Test类的定义和一个main方法,用于测试Test类中的equals()hashCode()方法。我们逐步解释如下:

  1. 私有字段
private String name;

定义了一个私有的String类型的字段name

  1. 构造方法
public Test(String name) {  
    this.name = name;  
}

构造方法接受一个字符串参数name,并将其赋值给Test对象的name字段。

  1. equals 方法
@Override  
public boolean equals(Object o) {  
    if (this == o) return true;  
    if (o == null || getClass() != o.getClass()) return false;  
    Test test = (Test) o;  
    return Objects.equals(name, test.name);  
}

这是重写的equals()方法,它用于比较两个Test对象是否相等。这里,相等性是基于name字段的。如果两个Test对象的name相同,它们就被视为相等。

  1. hashCode 方法
@Override  
public int hashCode() {  
    return name.length();  
}

这是重写的hashCode()方法。注意这里的实现是基于name字段的长度。这是一个有问题的实现,因为不同的字符串可能有相同的长度,从而导致不同的Test对象可能有相同的哈希码。

main 方法

  1. 创建两个Test对象:
Test t1 = new Test("test1");  
Test t2 = new Test("test2");

这里创建了两个不同的Test对象,它们的名字分别是"test1"和"test2"。

  1. 创建一个HashSet
Set<Test> set = new HashSet<>();

HashSet是一个不允许重复元素的集合。重复的元素是基于equals()hashCode()`方法判定的。

  1. set中添加对象:
set.add(t1);  
set.add(t2);

将两个Test对象加入到集合中。由于hashCode()方法是有问题的,即使两个对象是“相等”的(根据equals()方法),它们仍然可能被HashSet视为不同的对象。

  1. 打印set的大小:
System.out.println(set.size());  // 输出结果将是2,而不是我们期望的1

这里输出了set的大小,由于前面所述的问题,输出结果是2,而不是我们期望的1。这是因为尽管我们希望t1t2被视为相等并从集合中删除一个,但实际上并没有发生。

总结:当你重写equals()方法时,几乎总是需要同时重写hashCode()方法以确保它们的行为一致。否则,你的对象在Java集合中的行为可能会出现问题。