欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

详解Java中用于查找对象哈希码值的hashCode()函数

程序员文章站 2024-03-12 12:13:08
理解 hashcode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。 hashcode() 定...

理解
hashcode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。
hashcode() 定义在jdk的object.java中,这就意味着java中的任何类都包含有hashcode() 函数。
虽然,每个java类都包含hashcode() 函数。但是,仅仅当创建并某个“类的散列表”(关于“散列表”见下面说明)时,该类的hashcode() 才有用(作用是:确定该类的每一个对象在散列表中的位置;其它情况下(例如,创建类的单个对象,或者创建类的对象数组等等),类的hashcode() 没有作用。
上面的散列表,指的是:java集合中本质是散列表的类,如hashmap,hashtable,hashset。
也就是说:hashcode() 在散列表中才有用,在其它情况下没用。在散列表中hashcode() 的作用是获取对象的散列码,进而确定该对象在散列表中的位置。
我们都知道,散列表存储的是键值对(key-value),它的特点是:能根据“键”快速的检索出对应的“值”。这其中就利用到了散列码!
散列表的本质是通过数组实现的。当我们要获取散列表中的某个“值”时,实际上是要获取数组中的某个位置的元素。而数组的位置,就是通过“键”来获取的;更进一步说,数组的位置,是通过“键”对应的散列码计算得到的。
下面,我们以hashset为例,来深入说明hashcode()的作用。
假设,hashset中已经有1000个元素。当插入第1001个元素时,需要怎么处理?因为hashset是set集合,它允许有重复元素。
“将第1001个元素逐个的和前面1000个元素进行比较”?显然,这个效率是相等低下的。散列表很好的解决了这个问题,它根据元素的散列码计算出元素在散列表中的位置,然后将元素插入该位置即可。对于相同的元素,自然是只保存了一个。
由此可知,若两个元素相等,它们的散列码一定相等;但反过来确不一定。在散列表中,
1、如果两个对象相等,那么它们的hashcode()值一定要相同;
2、如果两个对象hashcode()相等,它们并不一定相等。
注意:这是在散列表中的情况。在非散列表中一定如此!

示例
我们来看一个具体的示例吧,

public class hashtest { 
  private int i; 
 
  public int geti() { 
    return i; 
  } 
 
  public void seti(int i) { 
    this.i = i; 
  } 
 
  public int hashcode() { 
    return i % 10; 
  } 
 
  public final static void main(string[] args) { 
    hashtest a = new hashtest(); 
    hashtest b = new hashtest(); 
    a.seti(1); 
    b.seti(1); 
    set<hashtest> set = new hashset<hashtest>(); 
    set.add(a); 
    set.add(b); 
    system.out.println(a.hashcode() == b.hashcode()); 
    system.out.println(a.equals(b)); 
    system.out.println(set); 
  } 
} 

这个输出的结果:

true 
false 
[com.ubs.sae.test.hashtest@1, com.ubs.sae.test.hashtest@1] 

以上这个示例,我们只是重写了hashcode方法,从上面的结果可以看出,虽然两个对象的hashcode相等,但是实际上两个对象并不是相等;,我们没有重写equals方法,那么就会调用object默认的equals方法,是比较两个对象的引用是不是相同,显示这是两个不同的对象,两个对象的引用肯定是不定的。这里我们将生成的对象放到了hashset中,而hashset中只能够存放唯一的对象,也就是相同的(适用于equals方法)的对象只会存放一个,但是这里实际上是两个对象a,b都被放到了hashset中,这样hashset就失去了他本身的意义了。
此时我们把equals方法给加上:

public class hashtest { 
  private int i; 
 
  public int geti() { 
    return i; 
  } 
 
  public void seti(int i) { 
    this.i = i; 
  } 
 
  <span style="color:#3366ff;"><strong>public boolean equals(object object) { 
    if (object == null) { 
      return false; 
    } 
    if (object == this) { 
      return true; 
    } 
    if (!(object instanceof hashtest)) { 
      return false; 
    } 
    hashtest other = (hashtest) object; 
    if (other.geti() == this.geti()) { 
      return true; 
    } 
    return false; 
  }</strong></span> 
 
  public int hashcode() { 
    return i % 10; 
  } 
 
  public final static void main(string[] args) { 
    hashtest a = new hashtest(); 
    hashtest b = new hashtest(); 
    a.seti(1); 
    b.seti(1); 
    set<hashtest> set = new hashset<hashtest>(); 
    set.add(a); 
    set.add(b); 
    system.out.println(a.hashcode() == b.hashcode()); 
    system.out.println(a.equals(b)); 
    system.out.println(set); 
  } 
} 

此时得到的结果就会如下:

true 
true 
[com.ubs.sae.test.hashtest@1] 

从结果我们可以看出,现在两个对象就完全相等了,hashset中也只存放了一份对象。

总结
1、hashcode的存在主要是用于查找的快捷性,如hashtable,hashmap等,hashcode是用来在散列存储结构中确定对象的存储地址的;

2、如果两个对象相同,就是适用于equals(java.lang.object) 方法,那么这两个对象的hashcode一定要相同;

3、如果对象的equals方法被重写,那么对象的hashcode也尽量重写,并且产生hashcode使用的对象,一定要和equals方法中使用的一致,否则就会违反上面提到的第2点;

4、两个对象的hashcode相同,并不一定表示两个对象就相同,也就是不一定适用于equals(java.lang.object) 方法,只能够说明这两个对象在散列存储结构中,如hashtable,他们“存放在同一个篮子里”。