hashcode 的作用

原文出处:http://blog.chenlb.com/2009/09/hashcode-effect.html

 

Java 对象 Hashcode 的作用是什么?可以联想数据结构的哈希表(散列表)、哈希函数。Object.hashCode() 就是一个哈希函数,用来计算散列值以实现哈希表这种数据结构。

看下哈希表结构:

哈希表

哈希表

在一个数组中存储对象时,通过 hashCode 得到的哈希值来计算数组的索引位置(通常是求余运算),然后根据这个索引位置进行存取。多个对象计算出来的索引位置相同(叫hash冲突)时,用链表保存。冲突怎么保证取到的就是自己呢?那么就要用到 Object.equals() 方法。

所以要把对象存储在像 hash table类似的数据结构(比如:HashSet)中,hashCode 与 equals 要成对实现。

Java Object hashCode api

返回该对象的哈希码值。支持该方法是为哈希表提供一些优点,例如,java.util.Hashtable 提供的哈希表。 hashCode 的常规协定是:
  • 在 Java 应用程序执行期间,在同一对象上多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是对象上 equals 比较中所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
  • 如果根据 equals(Object) 方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。
  • 以下情况 是必需的:如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么在两个对象中的任一对象上调用 hashCode 方法必定会生成不同的整数结果。但是,程序员应该知道,为不相等的对象生成不同整数结果可以提高哈希表的性能。

实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。)

上面的协定来看,一个对象的状态(这些状态不一定是所有字段,根据业务来看)没有改变时,多次调用 hashCode 必定相等。但是不同的对象可以有相等的 hashCode,不过尽量使不同的对象有不相等的 hashCode 可以提高哈希表的性能。

看下 Java Hashtable 的 get 与 put 实现:

 

	public synchronized V get(Object key) {   
	    Entry tab[] = table;   
	    int hash = key.hashCode();   
	    int index = (hash & 0x7FFFFFFF) % tab.length;   
	    for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {   
	        if ((e.hash == hash) && e.key.equals(key)) {   
	        return e.value;   
	        }   
	    }   
	    return null;   
	}  

 

先根据 key.hashCode 找数组的索引位置 indexhash & 0x7FFFFFFF 保证是正数。然后顺着找 hash equals 相等的。冲突链越长性能就越差。

put 方法:

 

 

public synchronized V get(Object key) {   
   Entry tab[] = table;   
   int hash = key.hashCode();   
   int index = (hash & 0x7FFFFFFF) % tab.length;   
   for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {   
       if ((e.hash == hash) && e.key.equals(key)) {   
       return e.value;   
       }   
   }   
    return null;   
}  

 

    先根据 key.hashCode 找数组的索引位置 index,hash & 0x7FFFFFFF 保证是正数。然后顺着找 hash 和 equals 相等的。冲突链越长性能就越差。

 

看 put 方法:

 

public synchronized V put(K key, V value) {   
   // Make sure the value is not null   
   if (value == null) {   
       throw new NullPointerException();   
   }   
 
   // Makes sure the key is not already in the hashtable.   
   Entry tab[] = table;   
   int hash = key.hashCode();   
    int index = (hash & 0x7FFFFFFF) % tab.length;   
    for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {   
        if ((e.hash == hash) && e.key.equals(key)) {   
        V old = e.value;   
        e.value = value;   
        return old;   
        }   
    }   
  
    modCount++;   
    if (count >= threshold) {   
        // Rehash the table if the threshold is exceeded   
        rehash();   
  
            tab = table;   
            index = (hash & 0x7FFFFFFF) % tab.length;   
    }   
  
    // Creates the new entry.   
    Entry<K,V> e = tab[index];   
    tab[index] = new Entry<K,V>(hash, key, value, e);   
    count++;   
    return null;   
}  

 

先看是否有相同的,有就替换。然后数组空间不够,会重换分配空间并数据重新散列保存。最后在冲突链头上插入。

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值