
下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、.如何正确实现 Java 中的 HashCode相等和 Hash Code从一般角度来看,Equality 是不错的,但是 hash code 更则具技巧性。如果我们在 hash code上多下点功夫,我们就能了解到 hash code 就是用在细微处去提升性能的。大部分的数据结构使用equals去检查是否他们包含一个元素。例如:12List list = Arrays.asList(a, b, c);booleancontains = list.contains(b);这个变量 contains 是true。因为他们是相等的,虽然b的实例化(instance)虽然不完全一样(再说一次,忽略S
2、tring interning)。将传递给 contains 的实例与每个元素进行比较很浪费时间。还好,整个这类数据结构使用了一种更高效的方法。它不会将请求的实例与每个元素比较,而是使用捷径,找到可能与之相等的实例,然后只比较这几项。这个捷径就是哈希码从对象计算出来的一个能代表该对象的整数值。与哈希码相同的实例不必相等,但相等的实例一定有相同的哈希码。(或者说应该有,我们稍后会对这个问题进行简单讨论)。这类的数据结构常常使用这种技术命名,在名称中加入 Hash 以便识别,其中最具代表性的就是 HashMap。一般情况下它们会这样进行: 添加一个元素的时候,使用它的哈希码来计算存放在内部数组(称
3、为桶)中的位置(序号)。 另一个不等同的元素如果具有相同的哈希码,它会被放在同一个桶中,与原来那个放在一起,比如把它们放在一个列表中。 如果传递一个实例给 contains 方法,会先计算它的哈希码来找到桶,只有同一个桶中的元素需要与这个实例进行比较。使用这种方法实现 contains 的情况很少,在理想的状态下根本不需要 equals 比较。将 equals、hashCode 定义在 Object 中。关于哈希的一些思考如果把 hashCode 作为一种快捷方式取决于其是否相等,那么只有一件事情我们需要关心:相等的对象应该有一致的哈希码。这也是为什么,如果我们覆写 equals 方法,就必须
4、创建一个匹配的 hashCode 实现!此外,实现 equal 应该是依据我们的实现而实现的,这可能会导致没有相同的哈希码,因为他们使用的是 Object 的实现。hashCode 约定从原文档引用:对于 hashCode 的一般约定: 在 Java 应用程序中,任何时候对同一对象多次调用 hashCode 方法,都必须一直返回同样的整数,对它提供的信息也用于对象的相等比较,且不会被修改。这个整数在两次对同一个应用程序的执行不中不需要保持一致。 如果两个对象通过 equals(Object) 方法来比较相等,那么这两个对象的 hashCode 方法必须产生同样的整型结果。 如果两个对象通过 e
5、quals(Object) 方法比较结果不等,这两个对象的 hashCode 不必产生同不整型结果。然而,开发者应该了解对不等的对象产生不同的整型结果有助于提高哈希表的性能。第一条反映了 equals 的一致性。第二条是我们在上面提到的要求。第三条陈述了我们下面要讨论的一个重要细节。实现 hashCodePerson.hashCode 有个很简单的实现:1234OverridepublicinthashCode() returnObjects.hash(firstName, lastName);通过计算相关字段的哈希码,再把这些哈希码组合起来得到 person 的哈希码。它们用 Object
6、的工具函数 hash 来参与计算。选择字段然而什么字段才是相关的.这些要求有助于回答这个问题:如果相等的对象必须有相同的哈希码,那么在计算哈希码的时候就不应该使用那些不用于相等性检查的字段。(否则,如果两个对象只有那些字段不同的话,它们会相等但哈希码不同。)所以用于计算哈希码的那些字段应该是用于相等性比较的那些字段的子集。默认情况下,它们会使用相同的字段,但有几个细节需要考虑。一致性第一是一致性要求。它应该经过非常严格的计算。如果有字段产生了变化,哈希码也应该允许变化(对于可变类来说,这往往是不可避免的),依赖哈希的数据结构并未准备应付这种情况。正如我们在上面看到的那样,哈希码用于确定一个元素
7、的桶,但是如果哈希相关的字段发生变化,并不会立即重新计算哈希码,而且内部的数组也不会更新。这就意味着,再对一个相等的对象甚至同一个对象的查询会失败!这个数据结构会计算当前的哈希码,这个哈希码与实例存入时的哈希码并不相同,这直接导致找错了桶。小结:最好不要用可变的字段来计算哈希码!性能哈希码可能最终会在每次调用 equals 的时候计算,这可能正好发生在代码中性能极为关键的部分,所以考虑性能是很有意义的。相比之下 equals 的优化空间就非常小。除非是使用了复杂的算法,或者使用的字段非常非常多,组合他们哈希码的计算成本可以忽略不计,因为这不可避免。但是应该考虑是否所有字段都需要包含在计算中!尤
8、其应该以审视的眼光来看待集合,例如计算列表和集合中所有元素的哈希码。需要根据不同的情况来考虑是否需要它们参与计算。如果性能是关键,使用 Object.hash 就可能不是最好的选择,因为它会为可变参数创建数组。一般的优化原则是:谨慎处理!使用一个公共哈希算法的,可能需要放弃集合,并在分析可能的改进之后进行优化。碰撞如果只关注性能,下面这个实例怎么样.1234OverridepublicinthashCode() return0;毫无疑问,它很快。而且相等的对象会有相同的哈希码,这也让我们觉得不错。还有个亮点,它不涉及可变的字段!但是,想想我们提到的桶是什么.这种情况下所有实例会被装进同一个桶中
9、!通常这会导致使用一个链表来容纳所有元素,这样的性能太糟糕了比如,每次执行 contains 都会对列表进行线性扫描。因此,我们得让每个桶里的内容尽可能的少!一个即使对非常相似的对象计算的哈希码也大不相同的算法,会是一个不错的开始。如何取得,一定程度上取决于选择的字段。我们用于计算的细节,更多时候是为了生成不同的哈希码。注意,这与我们对性能的想法完全相反。结果很有趣,用太多或者太少字段都会导致性能不佳。防止碰撞的算法是哈希算法的另一部分。计算哈希计算字段的哈希码最简单的办法就是直接调用这个字段的 hashCode。可以手工来进行合并。一个公共算法是从任意的某个数开始,让它与另一个数(通常是一个小素数)相乘,再加上一个字段的哈希码,然后重复:12345intprime = 31;intresult = 1;result = prime * result + (firstName = null) 0: firstName.hashCode();result = prime * result + (lastName = null) 0: lastName.hashCode();returnresult;这有可能造成溢出,但这不是什么
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 提供材料合同范本
- 租赁合同范本押金
- 5风儿轻轻吹(教学设计)-2023-2024学年道德与法治一年级下册统编版
- 6 综合与实践(教学设计)-2024-2025学年一年级上册数学北师大版
- 煤炭订货合同范本
- 2024-2025学年高中英语选修课趣味英语教学设计
- 3《我们班 他们班》第二课时(教学设计)-部编版道德与法治四年级上册
- 9 这些是大家的(教学设计)-2024-2025学年统编版道德与法治二年级上册
- 喷泉采购合同范本
- 担保公司融资合同范本
- BBC-商务英语会话
- 中等职业学校毕业生就业推荐表
- 2023年浙江首考读后续写真题讲评课件 高三英语二轮复习写作专项+
- 各期前列腺癌治疗的指南推荐
- 广东省五年一贯制考试英语真题
- ISO9001-2015质量手册及程序文件模板
- 山东省2022年高等教育专升本统一考试高等数学III试题及解析
- 现代厨房管理第一章第一节
- GB/T 694-2015化学试剂无水乙酸钠
- GB/T 6728-2017结构用冷弯空心型钢
- GB/T 6539-1997航空燃料与馏分燃料电导率测定法
评论
0/150
提交评论