在思考关于为什么要重写equal()和hashcode()方法的问题,个人理解如下:
Set类型是不允许重复元素的。所有会调用equal()和hashcode(),方法,每一个元素传进来都会产生一个hashcode值,用这个值与以前传入的值去做对比,当这个值以前存在过的,那就马上调用equal()方法去比较这个值别的属性去进一步判断这个值和以前传入的值是否相等,如果不相等,那么把他加入,如果相等那就舍弃。就相当与我们去判断一个值与其他值是否重复时要调用equal()函数,但是显然这个函数执行起来太浪费效率,所以在它执行前先加一部hashcode判断,这样如果hashcode的值不同,那么他们肯定不等,如果相同再调用equal()不迟。这样就增加效率,还有一个问题,为什么不一样的值会产生一样的hashcode。查看资料有以下说法:(一)hashCode是所有java对象的固有方法,如果不重载的话,返回的实际上是该对象在jvm的堆上的内存地址,而不同对象的内存地址肯定不同,所以这个hashCode也就肯定不同了。如果重载了的话,由于采用的算法的问题,有可能导致两个不同对象的hashCode相同。而且,还需要注意一下两点:
-
1)hashCode和equals两个方法是有语义关联的,它们需要满足:
A.equals(B)==true --> A.hashCode()==B.hashCode()
因此重载其中一个方法时也需要将另一个也重载。
2)hashCode的重载实现需要满足不变性,即一个object的hashCode不能前一会是1,过一会就变成2了。hashCode的重载实现最好依赖于对象中的final属性,从而在对象初始化构造后就不再变化。一方面是jvm便于代码优化,可以缓存这个hashCode;另一方面,在使用hashMap或hashSet的场景中,如果使用的key的hashCode会变化,将会导致bug,比如放进去时key.hashCode()=1,等到要取出来时key.hashCode()=2了,就会取不出来原先的数据。这个可以写一个简单的代码自己验证一下。
-
(二)哈希表是结合了直接寻址和链式寻址两种方式,所需要的就是将需要加入哈希表的数据首先计算哈希值,其实就是预先分个组,然后再将数据挂到分组后的链表后面,随着添加的数据越来越多,分组链上会挂接更多的数据,同一个分组链上的数据必定具有相同的哈希值,java中的hash函数返回的是int类型的,也就是说,最多允许存在2^32个分组,也是有限的,所以出现相同的哈希码就不稀奇了