一、首先确定euqals与==的区别:
1.对于基本数据类型来说:
(1).== 比较其存储的 “值”是否相等
(2).equals()无法作用于基本数据类型
2.对于引用类型来说:
(1).== 比较其所指向的地址是否相等
(2).equals()也是比较其所指向的地址是否相等;如果对equals()进行重写之后,则比较所指对象的内容。
二、为什么要重写equals()?
1.equals原型:
public boolean equals(Object obj) {
return (this == obj);
}
2.在没有重写equals()时,对于引用对象来说,equals原型中返回的"=="判断的是两个对象的内存地址是否相等。那么这就不符合我们的想要对比两个值是否相等的情况,比如我现在想比较两个String中的值是否相等:
s1 = new String("abc");
s2 = new String("abc");
s1==s2 //返回值是 false ,两个变量的内存地址不一样,也就是说它们指向的对象不一样,
s1.equals(s2)
//注意,此时的equals是未重写的,所以其内部调用的是【return (this == obj);】,
//因此其返回值为false
此时返回值为False,但他们的其实值都为abc,所以对比失败。因此,需要重写equals()方法。使得重写后的equals应该是比较对象内部的值是否相等,即s1.equals(s2)返回值为true。
三、为什么重写equals()方法也要重写hashCode()方法?
1.首先要确定为什么在使用equals之前要先使用hashCode方法。
我们都知道java中的List集合是有序的,因此是可以重复的,而set集合是无序的,因此是不能重复的,那么怎么能保证不能被放入重复的元素呢,但靠equals方法一样比较的话,如果原来集合中以后又10000个元素了,那么放入10001个元素,难道要将前面的所有元素都进行比较,看看是否有重复,这个效率可想而知会很低,因此hashCode就应遇而生了,java就采用了hash表,利用哈希算法(也叫散列算法),就是将对象数据根据该对象的特征使用特定的算法将其定义到一个地址上,那么在后面定义进来的数据只要看对应的hashcode地址上是否有值,如果有值的话就用equals比较,如果没有则直接插入,只要就大大减少了equals的使用次数,执行效率就大大提高了。
2.原生的hashCode()是什么样的?
原生的hashCode()值是根据内存地址换算出来的一个值。
3.hashCode()约定,摘自《Effective Java》第45页。
- 在一个应用程序执行期间,如果一个对象的equals方法做比较所用到的信息没有被修改的话,那么,对该对象调用hashCode方法多次,它必须始终如一地返回 同一个整数。在同一个应用程序的多次执行过程中,这个整数可以不同,即这个应用程序这次执行返回的整数与下一次执行返回的整数可以不一致。
- 如果两个对象根据equals(Object)方法是相等的,那么调用这两个对象中任一个对象的hashCode方法必须产生同样的整数结果。
- 如果两个对象根据equals(Object)方法是不相等的,那么调用这两个对象中任一个对象的hashCode方法,不要求必须产生不同的整数结果。然而,程序员应该意识到这样的事实,对于不相等的对象产生截然不同的整数结果,有可能提高散列表(hash table)的性能。
4.为什么要重写hashCode()?
翻译一下上面的hashCode约定:
(1).对一个未改变的值多次hashCode结果必定相同。
(1)当obj1.equals(obj2)为true时,obj1.hashCode() == obj2.hashCode()必须为true
(2)当obj1.hashCode() == obj2.hashCode()为false时,obj1.equals(obj2)必须为false
如果只重写了equals方法而没有重写hashCode方法的话,则会违反约定的第 (2)条:相等的对象必须具有相等的散列码(hashCode)!
此时若只是重写了equals方法,而没有重写hashCode时:
s1 = new String("abc");
s2 = new String("abc");
s1==s2
s1.equals(s2) //返回值为true
obj1.hashCode() == obj2.hashCode() //返回值为false
此时就不符合我们的规则(2),所以必须要重写hashCode方法(),来保证规则(2)成立。