为什么要重写hashCode()
为什么80%的码农都做不了架构师?>>>
首先说建议的情况: 比如你的对象想放到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简单的实现,我们来看看你就明白了:
//: containers/SimpleHashMap.java
// A demonstration hashed Map.
import java.util.*;
import net.mindview.util.*;public class SimpleHashMap<K, V> extends AbstractMap<K, V> {// Choose a prime number for the hash table// size, to achieve a uniform distribution:static final int SIZE = 997;// You can't have a physical array of generics,// but you can upcast to one:@SuppressWarnings("unchecked")LinkedList<MapEntry<K, V>>[] buckets = new LinkedList[SIZE];// List数组里每项是个List,数组下标是hashcode方法的返回值再经过散列函数得到的,相当于散列表的关键字,它亦代表着每个对象的关键字。(不能显示new一个泛型数组,但是你可以new一个泛型数组的引用,如有需要以后可以将普通数组转型为泛型数组)。[/color]public V put(K key, V value) {// 将这个对键值放进hashmap中。[/color]V oldValue = null;int index = Math.abs(key.hashCode()) % SIZE;// 这里就是通过散列函数对hashcode的返回值处理得到一个关键字,它代表了对象在数组里的位置,既是数组下标。[/color]if (buckets[index] == null)buckets[index] = new LinkedList<MapEntry<K, V>>();// 如果是第一次散列到这个数组下标,那么就新生成一个LinkedList,可以看到它里面保存的是MapEntry<K,V>键和值。[/color]LinkedList<MapEntry<K, V>> bucket = buckets[index];// 将这个LinkedList赋值给一个bucket(桶),以后就直接在这个bucket进行操作。[/color]MapEntry<K, V> pair = new MapEntry<K, V>(key, value);boolean found = false;ListIterator<MapEntry<K, V>> it = bucket.listIterator();while (it.hasNext()) {MapEntry<K, V> iPair = it.next();if (iPair.getKey().equals(key)) {// 如果已经存在同一个键值,那么就更新value。[/color]oldValue = iPair.getValue();it.set(pair); // Replace old with newfound = true;break;}}if (!found)buckets[index].add(pair);// 如果是一个新的键值,那么直接添加到这个LinkedList中。[/color]return oldValue;}public V get(Object key) {// 看hashmap是如何凭借hashcode方法快速定位到键值。[/color]int index = Math.abs(key.hashCode()) % SIZE;// 与put方法中的作用一样,生成数组下标,因为我存的时候就是存到这个地方的,那么我取的时候直接访问buckets[index]。[/color]if (buckets[index] == null)return null;// 直接访问这个数组下标的LinkedList,如果为null,则返回。[/color]for (MapEntry<K, V> iPair : buckets[index])// 为什么要用LinkedList,因为hashcode方法产生的散列码不能完全确定一个对象,也就是说会和其他对象发生“碰撞”,即散列到同一个数组下标,解决这个问题的组号办法就是定义一个List把它们保存起来,但是在这个List中,我们必须保证能用equals方法确定对象的身份,这也就是为什么很多人说hashcode()相等,equals()不一定相等,而equals()相等的两个对象,hashcode()一定相等。所以这里要直接在LinkedList执行线性查找。[/color]if (iPair.getKey().equals(key))return iPair.getValue();return null;}public Set<Map.Entry<K, V>> entrySet() {Set<Map.Entry<K, V>> set = new HashSet<Map.Entry<K, V>>();for (LinkedList<MapEntry<K, V>> bucket : buckets) {if (bucket == null)continue;for (MapEntry<K, V> mpair : bucket)set.add(mpair);}return set;}public static void main(String[] args) {SimpleHashMap<String, String> m = new SimpleHashMap<String, String>();m.putAll(Countries.capitals(25));System.out.println(m);System.out.println(m.get("ERITREA"));System.out.println(m.entrySet());}
} /* Output:
{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}
Asmara
[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方法就可以唯一确定对象的身份。这样说,想必已经很清楚了吧
转载于:https://my.oschina.net/leoson/blog/286452
为什么要重写hashCode()相关推荐
- JAVA中重写equals()方法的同时要重写hashcode()方法
object对象中的 public boolean equals(Object obj),对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象时,此方法才返回 true:注意:当此方法 ...
- 重写 equals 方法就一定要重写 hashCode 方法?其实有个前提
作者 l 会点代码的大叔(CodeDaShu) 如果问到 == 和 equals 的区别,相信很多程序员同学都能脱口而出:一个是判断地址,一个是判断内容. 但是如果继续追问:"你重写过 eq ...
- 为什么使用HashMap需要重写hashcode和equals方法_java常见面试题敲黑板了,HashMap最全的整理,大厂必考...
最近几天,在这样的大环境下显得疲惫不堪,但是我还是写下了这篇文章,希望对任何人都有用. HashMap是我们经常用到的数据结构,由数组和链表组成的数据结构如下图所示 上方是一张数组图片,数组里面每个地 ...
- 为什么使用HashMap需要重写hashcode和equals方法_为什么要重写 hashcode 和 equals 方法?...
1. 通过Hash算法来了解HashMap对象的高效性 2. 为什么要重写equals和hashCode方法 3. 对面试问题的说明 <Java 2019 超神之路> <Dubbo ...
- HashMap存自定义对象为什么要重写 hashcode 和 equals 方法?
HashMap的k放过自定义对象么? 当我们把自定义对象存入HashMap中时,如果不重写hashcode和equals这两个方法,会得不到预期的结果. class Key{private Integ ...
- hashcode相等的两个对象一定相等吗_为什么重写 equals方法时一定要重写hashCode方法?...
推荐阅读: 一线架构师总结SpringBoot,Cloud,Nginx与Docker,不信你搞不懂 47天洒热血复习,我终于"挤进"了字节跳动(附面经+学习笔记) 五年时间,从蘑菇 ...
- java 为什么重写equals一定要重写hashcode?
前言 最近复习,又看到了这个问题,在此记录和整理,通过例子来说明这种情况的原因,使大家可以清晰明白这个问题. 初步探索 首先我们要了解equals方法是什么,hashcode方法是什么. equals ...
- 为什么要重写hashcode( )和equals( )?
打个比方,一个名叫张三的人去住酒店,在前台登记完名字就去了99层100号房间,此时警察来前台找叫张三的这个人住在哪间房,经过查询,该酒店住宿的有50个叫张三的,需要遍历查询,查询起来很不方便. 那么就 ...
- 为什么重写equals一定要重写hashCode方法?
大家都知道,equals和hashcode是java.lang.Object类的两个重要的方法,在实际应用中常常需要重写这两个方法,但至于为什么重写这两个方法很多人都搞不明白. 下面我们看下Objec ...
- 为什么要重写hashcode()方法
主要原因是默认从Object继承来的hashCode是基于对象的ID实现的. 如果你重写了equals,比如说是基于对象的内容实现的,而保留hashCode的实现不变,那么很可能某两个对象明明是&qu ...
最新文章
- php table转json,html table表数据转Json格式示例代码分析
- Python把PDF文件中每页内容分离为独立图片文件
- codevs 4927 线段树练习5 线段树基本操作模板
- go 输入输出流(fmt)
- 火狐浏览器插件(XPI 文件)签名指南
- 【等价变换】—— 指数对数函数
- 工业大数据发展面临四方面挑战
- ansible 第一次练习
- 【深入JVM内核—原理、诊断与优化】第2期开课了
- 实时 摔倒识别 /运动分析/打架等异常行为识别/控制手势识别等所有行为识别全家桶 原理 + 代码 + 数据+ 模型 开源!
- 【编程知识】常用参考表对照表
- c语言编程开发app,C语言编程app
- html5 在线设计,推荐十款非常优秀的 HTML5 在线设计工具
- 照片文件与计算机系统,照片文件格式怎么修改
- 普元 AppServer 部署时页面提示部署失败,后台报错:Unable to load class org.apache.cxf.ws.policy.AssertionBuilder
- CSS3渐变属性:线性渐变和径向渐变用法教程
- OriginPro常用配置
- 西门子S7-1200和人机界面测试
- UDT 最新协议分析
- signature=f380c172efecdd0f7b9329d16d09ca45,Virtual Identity Signs in Online Communication
热门文章
- C++_一维数组案例_五只小猪称体重_案例元素逆置(调换)_案例冒泡排序---C++语言工作笔记020
- k8s核心技术-Pod(健康检查)_健康检查的方式_以及pod崩溃后如何处理---K8S_Google工作笔记0023
- security工作笔记008---springBoot springCloud中的security配置全解
- delphi Hi 和 High
- 终端中用命令成功修改linux~Ubuntu PATH环境变量
- 随想录(windows上cuda环境安装)
- 头像裁剪框html css,CSS3 clip-path实现的用户头像裁剪效果
- hci0 没反应_哄女朋友专用表情包~你说你没女朋友?先收藏着嘛,万一有了呢?...
- java计算器问题反馈,Java开发网 - 求教计算器问题(急~~~)
- 主板有电无法启动_主板通电但不能启动怎么回事