疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

揭开HashCode()和equals()的面纱


 

   

  在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)