在Java编程中,equals、hashCode和==运算符是常见的概念。它们在对象比较和存储中起着重要作用。本文将深入探讨这些概念的含义、用法和重要性。
"=="是一个运算符,其作用取决于比较的对象类型。
对于基本数据类型,"=="比较的是它们存储的值是否相等。
对于引用数据类型,"=="比较的是所指向对象的地址值是否相等,即是否是同一个对象。
Person p1 = new Person("123");
Person p2 = new Person("123");
int a = 10;
int b = 10;
System.out.println(a == b);//true
System.out.println(p1 == p2); //显然不是同一个对象,false
equals方法用于判断两个对象是否相等。它通过比较两个对象的地址是否相等来区分它们是否相等。如果没有对equals方法进行重写,则相当于“==”,比较的是引用类型的变量所指向的对象的地址值。
一般情况下,类会重写equals方法用来比较两个对象的内容是否相等。比如String类中的equals()是被重写了,比较的是对象的值。
hashCode的特性主要体现在其查找效率上,具有O(1)的复杂度,在Set和Map这种使用哈希表结构存储数据的集合中。
如果两个对象相同,则这两个对象的equals方法返回的值一定为true,两个对象的hashCode方法返回的值也一定相同。
如果两个对象返回的HashCode的值相同,但不能够说明这两个对象的equals方法返回的值就一定为true,只能说明这两个对象在存储在哈希表中的同一个桶中。
在Java中,当只重写了equals方法,未重写hashCode方法时,equals方法判断两个对象是否相等时,返回的是true。这是因为我们重写equals方法时,是对属性的比较。但判断两个对象的hashCode值是否相等时,返回的是false。在没有重写hashCode方法的情况下,调用的是Object的hashCode方法,返回的是本对象的hashCode值,两个对象不一样,因此hashCode值不一样。
在set和map中,首先判断两个对象的hashCode方法返回的值是否相等,如果相等然后再判断两个对象的equals方法。如果hashCode方法返回的值不相等,则直接会认为两个对象不相等,不进行equals方法的判断。因此在set添加对象时,因为hashCode值已经不一致,判断出p1和p2是两个对象,都会添加进set集合中,因此返回集合中数据个数为2。
重写hashCode方法后,其是对属性值的hash。p1和p2的属性值一致,因此p1.hashCode() == p2.hashCode()为true,再进行equals方法的判断也为true,认为是一个对象,因此set集合中只有一个对象数据。
如果两个对象的hashCode相同,它们是并不一定相同的,因为equals方法不相等而hashCode方法返回的值却有可能相同的,比如两个不同的对象hash到同一个桶中。
因此equals方法返回结果不相等,而hashCode方法返回的值却有可能相同。
这个是针对set和map这类使用hash值的对象来说的。
只重写equals方法,不重写hashCode方法:
有这样一个场景,有两个Person对象,可是如果没有重写hashCode方法只重写了equals方法,equals方法认为如果两个对象的name相同则认为这两个对象相同。这对于equals判断对象相等是没问题的。
对于set和map这类使用hash值的对象来说,由于没有重写hashCode方法,此时返回的hash值是不同的,因此不会去判断重写的equals方法,此时也就不会认为是相同的对象。
重写hashCode方法不重写equals方法:
不重写equals方法实际是调用Object方法中的equals方法,判断的是两个对象的堆内地址。而hashCode方法认为相等的两个对象在equals方法处并不相等。因此也不会认为是用一个对象。
因此重写equals方法时一定也要重写hashCode方法,重写hashCode方法时也应该重写equals方法。
对于普通判断对象是否相等来说,只重写equals是可以完成需求的,但是如果使用set,map这种需要用到hash值的集合时,不重写hashCode方法,是无法满足需求的。尽管如此,也一般建议两者都要重写,几乎没有见过只重写一个的情况。
来自一线程序员Seven的探索与实践,持续学习迭代中~
本文已收录于我的个人博客: https://www.seven97.top
公众号:seven97,欢迎关注~