equals()和hashCode()的区别

22
我想要一个关于equals()、"=="和hashCode()的简要定义。如果我运行以下代码,输出将为"true false 2420395 2420395"。但是我理解equals()方法比较字符串而"=="比较引用。但在输出中,hashCode()方法打印的引用号码对于两个字符串都相同,那么为什么"=="返回"false"呢?
    String str = "Name";
    String str1 = new String("Name");
    
    if (str.equals(str1))
        System.out.println("true");
    else
        System.out.println("false");

    if (str == str1)
        System.out.println("true");
    else
        System.out.println("false");
    
    System.out.println(str.hashCode());
    System.out.println(str1.hashCode());

我建议您再次阅读hashCode()的定义。没有所谓的引用编号。 - Peter Lawrey
7个回答

36

equals()hashCode() 方法在将实现这两个方法的对象添加到集合中时非常重要。如果实现不正确,可能会让你的生活变得一团糟。

equals():此方法检查传递给它作为参数的另一个对象是否等于调用此方法的对象。如果您不理解协议,则很容易错误地实现equals()方法。在重写此方法之前,需要记住以下“属性” -

  • 自反性:o1.equals(o1) - 这意味着一个对象(例如o1)应该等于它自己
  • 对称性:o1.equals(o2)当且仅当o2.equals(o1)
  • 传递性:o1.equals(o2) && o2.equals(o3) 意味着o1.equals(o3)
  • 一致性:只要o1和o2未修改,o1.equals(o2)返回相同的值
  • null比较:!o1.equals(null) - 这意味着任何可实例化的对象都不等于null。因此,如果将null作为参数传递给您的对象o1,则应返回false。
  • 哈希码值:o1.equals(o2)意味着o1.hashCode() == o2.hashCode()。这非常重要。如果定义了equals()方法,则必须同时定义hashCode()方法。还意味着如果您有两个相等的对象,则它们必须具有相同的hashCode,但反过来则不成立。

来自Java源代码

*
* @param   obj   the reference object with which to compare.
* @return  {@code true} if this object is the same as the obj
*          argument; {@code false} otherwise.
* @see     #hashCode()
* @see     java.util.HashMap
*/
public boolean equals(Object obj) {
   return (this == obj);

hashCode()方法:该方法返回一个整数值的hashCode(),并且被支持用于基于哈希的java.util.Collection类(如Hashtable、HashMap、HashSet等)的效果。如果一个类覆盖了equals()方法,那么它必须实现hashCode()方法。在覆盖此方法之前,您需要注意:

  • 每当在Java程序执行期间多次调用同一对象的hashCode()方法时,该方法必须始终返回相同的结果。整数结果不需要在程序的一个执行与同一程序的下一个执行之间保持一致。
  • 如果根据equals()方法两个对象是相等的,则在两个对象的每个hashCode()方法中调用必须返回相同的整数结果。因此,如果字段在equals()方法中未使用,则不得在hashCode()方法中使用。

  • 如果根据equals()方法两个对象是不相等的,则两个对象中的每个对象可以返回两个不同的整数结果或相同的整数结果(即,如果两个对象具有相同的hashCode()结果,并不意味着它们是相等的,但如果两个对象相等,则它们必须返回相同的hashCode()结果)。

根据Java源代码,就实际情况而言,java.lang.Object定义的hashCode方法确实为不同的对象返回不同的整数。(这通常通过将对象的内部地址转换为整数来实现)


我理解哈希码和内存地址是两个不同的东西,那么如何让不同对象的哈希码相同而它们又不相等呢? - Dhivakar
我理解哈希码和内存地址是两个不同的东西,这是正确的。实际上,这取决于JVM的实现方式。但是,如果您查看Java源代码/文档,您将了解到这一点。 - dgm
哈希码如何在不同对象中相同,但这些对象并不相等?不可能。如果两个对象不相等,它们的哈希码也应该不同。 - dgm

7

hashCode() 不返回对象的引用,而是计算出一个哈希值。这个哈希值是通过某种方式计算出来的。== 操作符不会使用 hashCode() 方法返回的值来比较对象,而是通过对象的引用值进行比较,这一点你说得正确。


2
以某种方式计算:确保相同的“内容”(“相等”的对象)最终具有相同的哈希码。对于字符串,它是所有字符的校验和。您可以在String的Javadoc中查看详细信息。 - Thilo

2
您可以阅读hashCode文档。简而言之,如果(obj1.equals(obj2)true,则obj1.hashCode()==obj2.hasCode()必须为true才能成为一个有效的实现
请注意,这并不意味着两个不同的对象不能共享相同的哈希码。实际上,这个例子是该方法的一个有效(但可怕)的实现:
class MyClass {
    public int hashCode() {return 0;}
}

2

equals()和hashCode()是不同的方法,hashCode()方法不应该用于检查两个对象引用是否相同。 原因:hashCode()只返回一个对象的int值,即使两个不同的对象可以有相同的hashCode整数。hashCode()返回的值是对象的哈希码,也就是对象的内存地址的十六进制表示。 equals()检查两个对象引用是否相同。如果两个对象相等,则它们的hashCode必须相同,但反过来不一定成立。


2

.equals()比较的是字符串的实际内容。

"=="运算符比较的是两个对象在内存中是否是相同的引用。如果你执行str = str1;,那么双等号运算符会返回true,因为它们指向内存中的同一个引用。

hashCode()以任意的方式返回对象的哈希值。只要该方法没有被覆盖,返回的值将始终是唯一的。如果.equals()返回true,则哈希码应该相同。


1

equals()只比较字符串,不检查字符串的引用。

但是'=='会检查引用和数据。

在第一个例子中,String str = "Name"只创建了一个对象,但在第二个例子中,创建了两个对象。

String str1 = new String("Name");

如果两个字符串的引用不同,那么它返回false。

1
  1. 正如其他人所说,'=='比较的是引用。但这两种方法只是执行某些可以被覆盖的操作的方法。
  2. 每个方法都有自己的功能。如果想知道它具体做了什么以及其含义,需要阅读文档。
  3. 您可以按任何方式重写这些方法。但请注意,您必须遵循JAVA文档中对这两种方法的规定。因为它们被其他类使用。例如,在尝试在列表中查找对象时会使用equals(),而JAVA类库提供的一些哈希表类中则使用.hashCode()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接