热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

探索equals()和hashCode()方法

探索equals()和hashCode()方法在根类Object中,实现了equals()和hashCode()这两个方法,默认:equals()是对两个对象的地址值进行的比较(即比较引用是否

探索equals()和hashCode()方法

  在根类Object中,实现了equals()和hashCode()这两个方法,默认:
  equals()是对两个对象的地址值进行的比较(即比较引用是否相同),用==实现。
  hashCode():计算出对象实例的哈希码。根类Object的hashCode()方法的计算依赖于对象实例的内存地址,即内存地址由哈希函数生成一个int值,故每个Object对象的hashCode都是唯一的;当然,当对象所对应的类重写了hashCode()方法时,结果就截然不同了。之所以有hashCode方法,是因为在批量的对象比较中,hashCode要比equals来得快,很多集合都用到了hashCode,比如Hashtable。

  • 两个obj,如果equals()相等,hashCode()一定相等
  • 两个obj,如果hashCode()相等,equals()不一定相等(Hash散列值有冲突的情况,虽然概率很低)。

  在集合中,判断两个对象是否相等的规则是:
第一步,如果hashCode()相等,则查看第二步,否则不相等;
第二步,查看equals()是否相等,如果相等,则两obj相等,否则还是不相等。

为什么选择hashCode方法?

  比如set集合存储数据的时候是怎样判断存进的数据是否已经存在。使用equals()方法呢,还是hashCode()方法。假如用equals(),那么存储一个元素就要跟已存在的所有元素比较一遍,比如已存入100个元素,那么存101个元素的时候,就要调用equals方法100次。
  但如果用hashcode()方法的话,每存一个数据就调用一次hashCode()方法,得到一个hashCode值及存入的位置。如果该位置不存在数据那么就直接存入,否则调用一次equals()方法,不相同则存,相同不存。这样下来整个存储下来不需要调用几次equals方法,虽然多了一次hashCode方法,但相对于前面来讲效率高了不少。

为什么要重写equals方法?

  因为Object的equals()方法默认是两个对象的引用的比较,意思就是指向同一内存则相等,否则不相等;如果你现在需要利用对象里面的值来判断是否相等,则重载equals()方法。记住:String,Double、Integer、Math这些类已经重写了equals()方法,比较的是对象的值。

改写equals时总是要改写hashCode

  如果不这样做到话,就会违反Object.hashCode的通用约定:相等的对象必须具有相等的散列码hashCode。根据一个类的equals方法,两个截然不同的实例有可能在逻辑上是相等的,但是,根据Object类的hashCode方法,它们仅仅是两个对象,对象hashCode方法返回两个看起来是随机的整数,而不是根据第二个约定要求的那样,返回两个相等的整数。从而导致该类无法与所有基于散列值(hash)的集合类结合在一起正常运作,这样的集合类包括hashMap、HashSet和Hashtable。比如new一个对象,再new一个内容相等的对象,调用equals方法返回的true,但他们的hashCode值不同,将两个对象存入HashSet中,hashCode值不同,都可以存进去,这样set中包含两个相等的对象。因为是先检索hashCode值,相等的情况下才会去比较equals方法。

hashCode方法使用介绍

  Hash表数据结构常识:
一、哈希表基于数组。
二、缺点:基于数组的,数组创建后难以扩展。某些哈希表被基本填满时,性能下降得非常严重。
三、没有一种简便的方法可以以任何一种顺序遍历表中数据项。
四、如果不需要有序遍历数据,并且可以提前预测数据量的大小,那么哈希表在速度和易用性方面是无与伦比的。

为什么HashCode对于对象是如此的重要(前面已经举了set的例子):

  HashMap和Hashtable,虽然它们有很大的区别,如继承关系不同,对value的约束条件(是否允许null)不同,以及线程安全性等有着特定的区别,但从实现原理上来说,它们是一致的。所以,我们只以Hashtable来说明:
  在java中,存取数据的性能,一般来说当然是首推数组,但是在数据量稍大的容器选择中,Hashtable将有比数组性能更高的查询速度。具体原因看下面的内容:
  Hashtable在存储数据时,一般先将该对象的HashCode和0x7FFFFFFF做与操作,因为一个对象的HashCode可以为负数,这样操作后可以保证它为一个正整数。然后以Hashtable的长度取模,得到该对象在Hashtable中的索引。

index = (o.hashCode() & 0x7FFFFFFF)%hs.length; 

  这个对象就会直接放在Hashtable的index位置,对于写入,这和数组一样,把一个对象放在其中的第index位置,但如果是查询,经过同样的算法,Hashtable可以直接从第index取得这个对象,而数组却要做循环比较。所以对于数据量稍大时,Hashtable的查询比数组具有更高的性能。

  事实上一个设计比较好的Hashtable,一般来说会比较平均地分布每个元素,因为Hashtable的长度总是比实际元素的个数按一定比例进行自增(负载因子一般为0.75左右),这样大多数的索引位置只有一个对象,而很少的位置会有几个元素。但是,hash冲突很难完全避免,可以看hash。一般Hashtable中的每个位置存放的是一个链表,对于只有一个对象的位置,链表只有一个首节点(Entry),Entry的next为null,同时保存hashCode,key,value属性,如果有相同索引的对象进来则会进入链表的下一个节点。如果同一个索引中有多个对象,根据HashCode和key可以在该链表中找到一个和查询的key相匹配的对象(equals方法)。
  对于一个对象,如果具有很多属性,把所有属性都参与散列,显然是一种笨拙的设计。因为对象的HashCode()方法被自动调用的很多,如果太多的对象参与了散列,那么需要的时间将会增加很多。可以挑选具有区分度的属性计算hash值,或者设立缓存,只要当参与散列的对象改变时才重新计算,否则调用缓存的hashCode,这可以从很大程度上提高性能。
  默认的实现是将对象内存地址转化为整数作为HashCode,这当然能保证每个对象具有不同的HasCode,但java语言并不能让程序员获取对象内存地址。
  请记住:如果你想有效的使用HashMap,你就必须重写在其的hashCode()。

还有两条重写hashCode()的原则:

  • 不必对每个不同的对象都产生一个唯一的hashCode,只要你的HashCode方法使get()能够得到put()放进去的内容就可以了。即“不为一原则”。
  • 生成hashCode的算法尽量使hashCode的值分散一些, 不要很多hashCode都集中在一个范围内,这样有利于提高HashMap的性能。即“分散原则”。

推荐阅读
  • 深入解析 Apache Shiro 安全框架架构
    本文详细介绍了 Apache Shiro,一个强大且灵活的开源安全框架。Shiro 专注于简化身份验证、授权、会话管理和加密等复杂的安全操作,使开发者能够更轻松地保护应用程序。其核心目标是提供易于使用和理解的API,同时确保高度的安全性和灵活性。 ... [详细]
  • 网易严选Java开发面试:MySQL索引深度解析
    本文详细记录了网易严选Java开发岗位的面试经验,特别针对MySQL索引相关的技术问题进行了深入探讨。通过本文,读者可以了解面试官常问的索引问题及其背后的原理。 ... [详细]
  • 本文介绍了多个关于JavaScript的书籍资源、实用工具和编程实例,涵盖从入门到进阶的各个阶段,帮助读者全面提升JavaScript编程能力。 ... [详细]
  • 本文探讨了在Java多线程环境下,如何确保具有相同key值的线程能够互斥执行并按顺序输出结果。通过优化代码结构和使用线程安全的数据结构,我们解决了线程同步问题,并实现了预期的并发行为。 ... [详细]
  • 本文探讨了如何在日常工作中通过优化效率和深入研究核心技术,将技术和知识转化为实际收益。文章结合个人经验,分享了提高工作效率、掌握高价值技能以及选择合适工作环境的方法,帮助读者更好地实现技术变现。 ... [详细]
  • 深入理解Java中的Collection接口与Collections工具类
    本文详细解析了Java中Collection接口和Collections工具类的区别与联系,帮助开发者更好地理解和使用这两个核心组件。 ... [详细]
  • 最近团队在部署DLP,作为一个技术人员对于黑盒看不到的地方还是充满了好奇心。多次咨询乙方人员DLP的算法原理是什么,他们都以商业秘密为由避而不谈,不得已只能自己查资料学习,于是有了下面的浅见。身为甲方,虽然不需要开发DLP产品,但是也有必要弄明白DLP基本的原理。俗话说工欲善其事必先利其器,只有在懂这个工具的原理之后才能更加灵活地使用这个工具,即使出现意外情况也能快速排错,越接近底层,越接近真相。根据DLP的实际用途,本文将DLP检测分为2部分,泄露关键字检测和近似重复文档检测。 ... [详细]
  • 作者:守望者1028链接:https:www.nowcoder.comdiscuss55353来源:牛客网面试高频题:校招过程中参考过牛客诸位大佬的面经,但是具体哪一块是参考谁的我 ... [详细]
  • PostgreSQL 10 离线安装指南
    本文详细介绍了如何在无法联网的服务器上进行 PostgreSQL 10 的离线安装,并涵盖了从下载安装包到配置远程访问的完整步骤。 ... [详细]
  • 深入理解Redis的数据结构与对象系统
    本文详细探讨了Redis中的数据结构和对象系统的实现,包括字符串、列表、集合、哈希表和有序集合等五种核心对象类型,以及它们所使用的底层数据结构。通过分析源码和相关文献,帮助读者更好地理解Redis的设计原理。 ... [详细]
  • 本文介绍了一种解决二元可满足性(2-SAT)问题的方法。通过具体实例,详细解释了如何构建模型、应用算法,并提供了编程实现的细节和优化建议。 ... [详细]
  • 本文探讨了高质量C/C++编程的最佳实践,并详细分析了常见的内存错误及其解决方案。通过深入理解内存管理和故障排除技巧,开发者可以编写更健壮的程序。 ... [详细]
  • 本文深入探讨了 Redis 的两种持久化方式——RDB 快照和 AOF 日志。详细介绍了它们的工作原理、配置方法以及各自的优缺点,帮助读者根据具体需求选择合适的持久化方案。 ... [详细]
  • 本文将深入探讨如何在不依赖第三方库的情况下,使用 React 处理表单输入和验证。我们将介绍一种高效且灵活的方法,涵盖表单提交、输入验证及错误处理等关键功能。 ... [详细]
  • 堆是一种常见的数据结构,广泛应用于计算机科学领域。它通常表示为一棵完全二叉树,并可通过数组实现。堆的主要特性是每个节点的值与其父节点的值之间存在特定的关系,这使得堆在优先队列和排序算法中非常有用。 ... [详细]
author-avatar
wzcheng1984
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有