首先说建议的情况: 比如你的对象想放到Set集合或者是想作为Map的key时(非散列的Set和Map,例如TreeSet,TreeMap等),那么你必须重写equals()方法,这样才能保证唯一性。当然,在这种情况下,你不想重写hashCode()方法,也没有错。但是,对于良好的编程风格而言,你应该在重写equals()方法的同时,也重写hashCode()方法。
然后再说说必须重写hashCode()的情况:
如果你的对象想放进散列存储的集合中(比如:HashSet,LinkedHashSet)或者想作为散列Map(例如:HashMap,LinkedHashMap等等)的Key时,在重写equals()方法的同时,必须重写hashCode()方法。
这里我想讲讲sun的设计者为什么需要设计hashcode方法,也许这样你就应该知道什么时候该重写它了。
数据结构有一种为了提高查找的效率而存在的数据结构——散列表,散列表其实是普通数组概念的推广,因为可以对数组进行直接寻址,故可以再O(1)时间内访问数组的任意元素,thinking in java中有个对hashmap简单的实现,我们来看看你就明白了:
1.//: containers/SimpleHashMap.java
2.// A demonstration hashed Map.
3.import java.util.*;
4.import net.mindview.util.*;
5.
6.public class SimpleHashMap<K,V> extends AbstractMap<K,V> {
7. // Choose a prime number for the hash table
8. // size, to achieve a uniform distribution:
9. static final int SIZE = 997;
10. // You can't have a physical array of generics,
11. // but you can upcast to one:
12. @SuppressWarnings("unchecked")
13. LinkedList<MapEntry<K,V>>[] buckets =
14. new LinkedList[SIZE];//List数组里每项是个List,数组下标是hashcode方法的返回值再经过散列函数得到的,相当于散列表的关键字,它亦代表着每个对象的关键字。(不能显示new一个泛型数组,但是你可以new一个泛型数组的引用,如有需要以后可以将普通数组转型为泛型数组)。
15. public V put(K key, V value) {//将这个对键值放进hashmap中。
16. V oldValue = null;
17. int index = Math.abs(key.hashCode()) % SIZE;//这里就是通过散列函数对hashcode的返回值处理得到一个关键字,它代表了对象在数组里的位置,既是数组下标。
18. if(buckets[index] == null)
19. buckets[index] = new LinkedList<MapEntry<K,V>>();//如果是第一次散列到这个数组下标,那么就新生成一个LinkedList,可以看到它里面保存的是MapEntry<K,V>键和值。
20. LinkedList<MapEntry<K,V>> bucket = buckets[index];//将这个LinkedList赋值给一个bucket(桶),以后就直接在这个bucket进行操作。
21. MapEntry<K,V> pair = new MapEntry<K,V>(key, value);
22. boolean found = false;
23. ListIterator<MapEntry<K,V>> it = bucket.listIterator();
24. while(it.hasNext()) {
25. MapEntry<K,V> iPair = it.next();
26. if(iPair.getKey().equals(key)) {//如果已经存在同一个键值,那么就更新value。
27. oldValue = iPair.getValue();
28. it.set(pair); // Replace old with new
29. found = true;
30. break;
31. }
32. }
33. if(!found)
34. buckets[index].add(pair);//如果是一个新的键值,那么直接添加到这个LinkedList中。
35. return oldValue;
36. }
37. public V get(Object key) {//看hashmap是如何凭借hashcode方法快速定位到键值。
38. int index = Math.abs(key.hashCode()) % SIZE;
//与put方法中的作用一样,生成数组下标,因为我存的时候就是存到这个地方的,那么我取的时候直接访问buckets[index]。
39. if(buckets[index] == null) return null;//直接访问这个数组下标的LinkedList,如果为null,则返回。
40. for(MapEntry<K,V> iPair : buckets[index])//为什么要用LinkedList,因为hashcode方法产生的散列码不能完全确定一个对象,也就是说会和其他对象发生“碰撞”,即散列到同一个数组下标,解决这个问题的组号办法就是定义一个List把它们保存起来,但是在这个List中,我们必须保证能用equals方法确定对象的身份,这也就是为什么很多人说hashcode()相等,equals()不一定相等,而equals()相等的两个对象,hashcode()一定相等。所以这里要直接在LinkedList执行线性查找。
41. if(iPair.getKey().equals(key))
42. return iPair.getValue();
43. return null;
44. }
45. public Set<Map.Entry<K,V>> entrySet() {
46. Set<Map.Entry<K,V>> set= new HashSet<Map.Entry<K,V>>();
47. for(LinkedList<MapEntry<K,V>> bucket : buckets) {
48. if(bucket == null) continue;
49. for(MapEntry<K,V> mpair : bucket)
50. set.add(mpair);
51. }
52. return set;
53. }
54. public static void main(String[] args) {
55. SimpleHashMap<String,String> m =
56. new SimpleHashMap<String,String>();
57. m.putAll(Countries.capitals(25));
58. System.out.println(m);
59. System.out.println(m.get("ERITREA"));
60. System.out.println(m.entrySet());
61. }
62.} /* Output:
63.{CAMEROON=Yaounde, CONGO=Brazzaville, CHAD=N'djamena, COTE D'IVOIR (IVORY COAST)=Yamoussoukro, CENTRAL AFRICAN REPUBLIC=Bangui, GUINEA=Conakry, BOTSWANA=Gaberone, BISSAU=Bissau, EGYPT=Cairo, ANGOLA=Luanda, BURKINA FASO=Ouagadougou, ERITREA=Asmara, THE GAMBIA=Banjul, KENYA=Nairobi, GABON=Libreville, CAPE VERDE=Praia, ALGERIA=Algiers, COMOROS=Moroni, EQUATORIAL GUINEA=Malabo, BURUNDI=Bujumbura, BENIN=Porto-Novo, BULGARIA=Sofia, GHANA=Accra, DJIBOUTI=Dijibouti, ETHIOPIA=Addis Ababa}
64.Asmara
65.[CAMEROON=Yaounde, CONGO=Brazzaville, CHAD=N'djamena, COTE D'IVOIR (IVORY COAST)=Yamoussoukro, CENTRAL AFRICAN REPUBLIC=Bangui, GUINEA=Conakry, BOTSWANA=Gaberone, BISSAU=Bissau, EGYPT=Cairo, ANGOLA=Luanda, BURKINA FASO=Ouagadougou, ERITREA=Asmara, THE GAMBIA=Banjul, KENYA=Nairobi, GABON=Libreville, CAPE VERDE=Praia, ALGERIA=Algiers, COMOROS=Moroni, EQUATORIAL GUINEA=Malabo, BURUNDI=Bujumbura, BENIN=Porto-Novo, BULGARIA=Sofia, GHANA=Accra, DJIBOUTI=Dijibouti, ETHIOPIA=Addis Ababa]
怎样?现在应该知道hashcode方法的作用了吧,它就是用来提高效率的,有句话说得好:为速度而散列。因为散列的Set和Map是基于hashcode方法来查找对象的,所以你在使用这些类的时候一定要覆盖hashcode方法,而非散列的Set和Map,例如TreeSet,TreeMap等,它们只需equals方法就可以唯一确定对象的身份。这样说,想必已经很清楚了吧。
分享到:
相关推荐
重写equals和hashcode方法,学习和进步
Java重写equals同时需要重写hashCode的代码说明,以及如何重写hashCode方法,此代码演示按照effective java书籍说明的重写思路。代码中演示了使用集合存储对象,并且对象作为key,需重写equals和hashCode.
为什么重写equals方法,还必须要重写hashcode方法
面试官瞬间就饱了,重写equals函数,需要重写hashCode函数吗? 面试官问我,为什么重写equals函数,必须重写hashCode函数,我当时就懵住了。 然后扯天扯地,然后面试官瞬间就饱了,痛定思痛,写下这篇博客 首先看...
关于重写equals,hashcode以及compareTo方法!
主要介绍了重写hashCode()和equals()方法详细介绍,涉及重写equals()方法,重写hashCode()方法,重写equals()而不重写hashCode()的风险等相关内容的介绍,具有一定借鉴价值,需要的朋友可以参考下
6、什么时候需要重写hashCode()方法?7、重写hashCode()方法: 1、hashCode与equals两者之间的关系 如果两个对象相同(即用equals比较返回true),那么它们的hashCode值一定要相同!!!! 如果两个对象不同(即用...
Object 类是所有类的父类,其 equals 方法比较的是两个对象的引用指向的地址,hashcode 是一个本地方法,返回的是对象地址值。他们都是通过比较地址来比较对象是否相等的
首先我们先来看下String类的源码:可以发现String是重写了Object类的equals方法的,并且也重写了hashcode方法
NULL 博文链接:https://zpointer.iteye.com/blog/1058337
主要给大家介绍了关于java中为什么重写equals时必须重写hashCode方法的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
下面小编就为大家带来一篇java中重写equals()方法的同时要重写hashcode()方法(详解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
equals():反映的是对象或变量具体的值,即两个对象里面包含的值--可能是对象的引用,也可能是值类型的值。 hashCode():计算出对象实例的...当然,当对象所对应的类重写了hashCode()方法时,结果就截然不同了。
NULL 博文链接:https://alpha2009.iteye.com/blog/570322
主要介绍了Java重写equals及hashcode方法流程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
主要介绍了如何在IDEA中对 hashCode()和 equals() 利用快捷键快速进行方法重写,需要的朋友可以参考下
在这篇文章中,我将告诉大家我对hashCode和equals方法的理解。我将讨论他们的默认实现,以及如何正确的重写他们。我也将使用Apache Commons提供的工具包做一个实现。 hashCode()和equals()定义在Object类中,这...
原因是因为,在Java自带的容器HashMap和HashSet中, 都需同时要用到对象的hashCode()和equals()方法来进行判断,然后再插入删除元素,这点我们一会再谈。 那么我们还是单独来看hashCode(),为什么HashMap需要用到...
为什么重写 equals() 时必须重写 hashCode() 方法? String String、StringBuffer、StringBuilder 的区别? String 为什么是不可变的? 字符串拼接用“+” 还是 StringBuilder? String#equals() 和 Object#equals() ...
个人学习终结成果:为什么要重新equals和hashCode方法?如何重写?站好马步需从j2se基础开始