2. hashCode VS equals
2.1 hashCode介绍
hashCode()的作用是获取哈希码,也成为散列码;它实际上返回一个int整数。这个哈希码的作用是确定该对象在哈希表的索引位置。hashCode()定义在JDK的Object中,这就意味java中任何类都包含hashCode()函数。
2.2 equals介绍
equals的作用也是判断两个对象是否相等,如果对象重写了equals()方法,比较两个对象的内容是否相等;如果没有重写,比较两个对象的地址是否相等,等价于“==”。同样的,equals()定义在JDK的Object中,这就意味着java中的任何类都包含equals()函数。
2.3 hashCode()和equals()关系
2.3.1 不会创建“类对应的散列表”
不会创建“类对应的散列表”是指我们不会再HashSet、HashTable、HashMap等本质是散列表的数据结构中用到该类。例如不会创建该类的HashSet集合。
这种情况下,该类的hashCode()和equals()没有关系。
equals()用来比较该类的两个对象是否相等,
hashCode()在此场景没有任何作用。
2.3.2 会创建“类对应的散列表”
会创建“类对应的散列表”是指我们会再HashSet、HashTable、HashMap等本质是散列表的数据结构中用到该类。例如会创建该类的HashSet集合。
在这种情况下,该类的hashCode()和equals()是有关系的:
- 如果两个对象相等,那么他们的hashCode值一定相同。这里的相等是指,通过equals()比较两个对象时返回true。
- 如果两个对象hashCode()相等,他们并不一定相等。因为在散列表中,hashCode()相等,即两个键值对的哈希值相等。然而哈希值相等,并不一定能得出键值对相等,此时就会出现所谓的哈希冲突场景。
如果类使用散列表的集合对象中,要判断两个对象是否相同,除了要覆盖equals()之外,也要覆盖hashCode()否则equals()无效。
2.4 复写hashCode的诀窍
一个好的hashCode的方法目标:为不相等的对象产生不相等的散列码,同样的,相等的对象必须拥有相等的散列码。
31*result + c:乘法使hash值依赖于域的顺序,如果没有乘法那么所有顺序不同的字符串String对象都会有一样的hash值。31是一个奇素数,如果是偶数,并且乘法溢出的话,信息会丢失,31有个很好的特性就是31*i ==(i<<5)-i,即2的5次方减1,虚拟机会优化乘法作为移位操作的。
【例如Objects里的方法,计算对象hash值】
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
【例如String里的方法,计算单个属性hash值】
public static int hashCode(Object a[]) {
if (a == null)
return 0;
int result = 1;
for (Object element : a)
result = 31 * result + (element == null ? 0 : element.hashCode());
return result;
}
网友评论