在JAVA中,我们通常知道
- 如果两个对象相同(equal()返回true),那么他们的hashcode值一定相同。
- 如果两个对象不同(equal()返回false),他们的hashcode值也可能相同
为什么会出现这样的情况,hashCode()和equals()到底有什么不同。下面就让我们来详细了解他们
HashCode的定义
HashCode也称为哈希值或者散列值。在JAVA中,hashCode值由hashCode()方法返回。hashCode()方法在Object类中,因此所有的对象都可以通过hashCode()方法求出其对应的哈希值。下面给出Object类中的hashCode()方法
public int hashCode() {
int lockWord = shadow$_monitor_;
final int lockWordMask = 0xC0000000; // Top 2 bits.
final int lockWordStateHash = 0x80000000; // Top 2 bits are value 2 (kStateHash).
if ((lockWord & lockWordMask) == lockWordStateHash) {
return lockWord & ~lockWordMask;
}
return System.identityHashCode(this);
}
identityHashCode()方法是System类中的静态方法,根据对象内存地址来计算哈希值。
hashCode()方法可以被override,例如String类中的hashcode()
@Override
public int hashCode() {
int hash = hashCode;
if (hash == 0) {
if (count == 0) {
return 0;
}
final int end = count + offset;
final char[] chars = value;
for (int i = offset; i < end; ++i) {
hash = 31*hash + chars[i];
}
hashCode = hash;
}
return hash;
}
重点在里面的那个for循环,JDK1.7u4文档上解释为
s[0]*31^(n-1) + s[1]*31^(n-2) + … + s[n-1] 这种算法。通过这样来求得哈希值。
上面是String类中的hashcode()方法,我们还有Double ,float ,AbstractList等类都重写了这个方法来获取哈希值。
哈希值的用处
到这里为止我们知道了哈希值的定义。那么我们为什么需要用到hashCode()这个方法呢?
效率!效率!效率!重要的事情说三遍。举个例子,当我们在Set数据结构中插入新的数据时,首先需要查重,那么判别在集合中是否已经存在该数据对象了就显得至关重要了。我们可以用equals()方法来从头到尾遍历,但是显得效率不高。如果我把集合分成若干个小组,我知道这个待插入数据在哪个小组里面,直接去那个小组查找,这样就显得高效多了。哈希值就好比这个小组序号。找到小组后再根据equals()方法来逐个查找是否含有重复的对象。
当两个不同对象产生了相同的哈希值时,我们管这种现象叫做碰撞。可以这样来考虑,我们把某个集合看成一个“链表数组”,哈希值相同表示在同一个数组元素中(也就是在同一个链表中),如果发生了碰撞,那么新的对象将会被添加到链表的末端。
以上就是为什么hashcode的用途浅析了,而HashSet,HashMap,HashTable就是它的典型应用。
equals()方法注意事项
假设x,y,z为非空对象
- 对称 x.equals(y)和y.equals(x)对象的返回值相同
- 反射 x.equals(x)返回true.
- x.equals(null)返回false.
- x.equals(不同类型的对象y)返回false
- 类推性 如果x.equals(y),y.equals(z),那么z.equals(x)