黑马程序员技术交流社区

标题: hashcode()和equals()方法 [打印本页]

作者: 罗利华    时间: 2013-1-4 13:22
标题: hashcode()和equals()方法
本帖最后由 修心者 于 2013-1-4 14:50 编辑

hashcode()和equals()方法,具体起什么作用?

作者: 希望的曙光    时间: 2013-1-4 13:30
本帖最后由 希望的曙光 于 2013-1-4 13:46 编辑

   SUM
  如果你的对象想散列存储的集合中或者想作为散列Map的Key时(HashSet、HashMap、Hashtable等)那么你必须重写equals()方法,这样才能保证唯一性。在重写equals()方法的同时,必须重写hashCode()方  法?当然,在这种情况下,你不想重写hashCode()方法,也没有错,但是sun建议这么做,重写hashCode只是技术要求(为了提高效率)。

      当在散列集合中放入key时,将自动查看key对象的hashCode值,若此时放置的hashCode值和原来已有的hashCode值相等,则自动调用equals()方法,若此时返回的为true则表示该key为相同的key值,只会存在一份。

      Object中关于hashCode和equals方法的定义为:
1.public boolean equals(Object obj) {  
2.    return (this == obj);  
3.}  
4.public native int hashCode();  

      基类的hashCode是一个native方法,访问操作系统底层,它得到的值是与这个对象在内存中的地址有关。

      Object的不同子类对于equals和hashCode方法有其自身的实现方式,如Integer和String等。
             equals相等的,hashCode必须相等
             hashCode不等的,则 equals也必定不等。
            hashCode相等的 equals不一定相等(但最好少出现 hashCode相等的情况)。

      HashMap的put(K, Value)方法提供了一个根据K的hashCode来计算Hash码的方法hash()

1.transient Entry[] table;  
2.public V put(K key, V value) {  
3.    if (key == null)  
4.        return putForNullKey(value);        //HashMap支持null的key  
5.    int hash = hash(key.hashCode());        //根据key的hashCode计算Hash值  
6.    int i = indexFor(hash, table.length);   //搜索指定Hash值在对应table中的索引  
7.    for (Entry<K,V> e = table; e != null; e = e.next) {    //在i索引处Entry不为空,循环遍历e的下一个元素  
8.        Object k;  
9.        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {  
10.            V oldValue = e.value;  
11.            e.value = value;  
12.            e.recordAccess(this);  
13.            return oldValue;  
14.        }  
15.    }  
16.    //若i索引处Entry为null,表明此处还没有Entry  
17.    modCount++;  
18.    addEntry(hash, key, value, i);  //将key、value添加到i索引处  
19.    return null;  
20.}  
21.  
22.static int hash(int h) {  
23.    h ^= (h >>> 20) ^ (h >>> 12);  
24.    return h ^ (h >>> 7) ^ (h >>> 4);  
25.}  

     对于任意给定的对象,只有它的hashCode()返回值相同,那么程序调用hash(int h)方法所计算得到的Hash码值总是相同的。接下来会调用indexFor(int h, int length)方法来计算该对象应该保存在table数组的哪个索引处。

Java代码  
1.static int indexFor(int h, int length) {  
2.    return h & (length-1);  
3.}  
     它总是通过h & (table.length - 1)来得到该对象的保存位置--而HashMap底层数组的长度总是2的n次方,这样就保证了得到的索引值总是位于table数组的索引之内。
      当通过key-value放入HashMap时,程序就根据key的hashCode()来觉得Entry的存储位置:若两个Entry的key的hashCode()相同那么他们的存储位置相同;若两个Entry的key的equals()方法返回true则新添加Entry的value将覆盖原有Entry的value,但key不会覆盖;若两个Entry的key的equals()方法返回false则新加的Entry与集合中原有的Entry形成Entry链。

1.void addEntry(int hash, K key, V value, int bucketIndex) {  
2.    Entry<K,V> e = table[bucketIndex];  
3.    table[bucketIndex] = new Entry<K,V>(hash, key, value, e);  
4.    if (size++ >= threshold)     //size保存了HashMap中所包含的key-value对的数量  
5.        resize(2 * table.length);   //扩充table对象的长度2倍  
6.}  

     HashSet的add(E)的实现是通过HashMap的put方法来实现的。(HashSet内部是通过HashMap来实现的,TreeSet则是通过TreeMap来实现的)
1.public V get(Object key) {  
2.    if (key == null)  
3.        return getForNullKey();  
4.    int hash = hash(key.hashCode());  
5.    int i = indexFor(hash, table.length);  
6.    for (Entry<K,V> e = table; e != null; e = e.next) {  
7.        Object k;  
8.        if (e.hash == hash && ((k = e.key) == key || key.equals(k)))  
9.            return e.value;  
10.    }  
11.    return null;  
12.}  
    根据key的hashCode计算器Hash值,然后取得该Hash值在表table的索引,取得该索引i对应的table中的Entry,判断key的equals()。

作者: 罗利华    时间: 2013-1-4 13:43
希望的曙光 发表于 2013-1-4 13:30
SUN .

辛苦了,谢谢,




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2