众所周知,Java中的List集合是有序的但Set集合是无序的(即元素不能重复),那如何保证两个元素不是重复的呢?那就是重写hashcode和equals方法来进行去重。
这里采用了数组+链表+红黑树(此处不考虑红黑树)的结构进行组织。根据要存储元素的值先通过计算其hashcode的值来确定元素应该放在数组上的几号下标位置。对于普通对象会从这个对象的存储地址的本身或者从中抽取的一部分作为初始哈希值,再对这个哈希值进行位运算或者加减乘除操作来使数值更加随机以及分散来减少哈希冲突最终得到哈希值。源码如下:
public native int hashCode();
而对于数组对象则是遍历数组,对它们对应的hash值进行相加来生成对应的hashcode值,源码如下:
public int hashCode() {
int h = 0;
for (int i = 0; i < length; i++) {
h = 31 * h + elementData[i].hashCode();
}
return h;
}
在得到hashcode的值后也就确定了元素在数组中的下标位置,这时再根据equals方法来判断两个对象的内容是否也是一样的,若是不重写equals将会调用object中的equals方法,源码如下:
public boolean equals(Object obj) {
return (this == obj);
}
从源码可以看出只有根据业务场景重写equals方法才可以判断元素的内容是否一样,否则调用object类的equals方法只是判断两个对象的引用地址是否一样,这样将失去equals的意义。
小结:比较两个对象是否一样时,会先通过计算hashcode的值来判断是否在hash表数组中的同一位置上,再通过equals方法判断两个对象的内容是否一致。因此hashcode相同的对象equals不一定相同,但equals相同的对象hashcode一定相同,并且在查询时,先判断hashcode也可以提高查询速率。