java中hashcode的作用

在上一篇文章Java中hashcode方法与equals方法关联关系的直观解释中说明了hashcode方法与equals方法的联系,但是hashcode返回的整数是什么呢,以及hashcode的作用是什么呢?

equals、hashcode、内存地址

  • Object默认的equals方法通过(虚拟)内存地址来比较两个对象是否相等
  • 要区别两个对象,我们想到的最直观的方式就是使用它们的内存地址来进行区分,这也是Object.equals()的做法。
  • 如果我们想区分两个元素位于不同内存地址的对象是否相同,那我们如果还是使用内存地址那肯定是不可行的,那我重新了equals方法之后不久可以比较了吗,那我们还需要hashcode干嘛呢,答案是提高效率,比如我们有个Set集合,我们每插入一个元素就要知道是否有重复,这时候我们就需要利用equals方法比较,但是如果集合元素数量很多,那比较起来就需要全部遍历,这时候hashcode就是来解决这一问题的。它通过计算得到,帮助我们快速定位到一定的区域再挨个进行比较,缩小了比较的范围,甚至是确切的知道告诉我们不存在重复。

hashcode是什么

其实hashcode就是一个对象的身份证号,但是它是允许重复的。你可以这样理解,每个对象都需要一个身份标识,来区分它和其他的对象不同,但是由于一些限制因素(下面的斜体解释了它),我们不可能实现每一个对象都有一个唯一的标识,而是使用了一个叫做hashcode的编号。

有位大神验证了hashcode方法返回值到底是不是对象内存地址Java的Object.hashCode()的返回值到底是不是对象内存地址结论是:hashCode返回的并不一定是对象的(虚拟)内存地址,具体取决于运行时库和JVM的具体实现。也就是说某些情况下使用内存地址,而有些情况不使用。

为什么不使用内存地址来进行区分呢?我的猜测:

限制因素:hashcode是每个对象都有的一个int值,首先int值本身就是有上下限的,long也是,不可能有无穷个对象无穷个hashcode值和它对应,它们的值一定有重复的,你可能会说内存空间是一定的,你可以表示内存地址那就可以把这个内存地址拿来作为hashcode的返回值啊,我的理由1)如果完全使用内存地址跨平台特性会受到一定影响,至少pc上地址总线的长度可能不同;2)操作系统其实是可以使用虚拟内存的,理论上它的实际使用的内存空间会比真正的内存要大,在运行程序的时候把数据和代码换入换出,这时候我们的long,int恐怕都装不下这么大的地址数字。

hashcode的作用
——散列表中作为一个对象的身份标识

Java中散列表的实现主要有两个,一个是线程安全的HashTable,一个是线程不安全的HashMap。而HashSet其实是利用HashMap实现的,里面包含了一个HashMap类型的引用。
先看一张图:
这里写图片描述
这张图形象的表示出了HashMap的实现模型,HashMap是利用数组与链表结合的方式实现的。可以看到它并非是线性的。

试着非线性的方式思考,线性表中数组这种数据结构具有查询快但是删除、插入慢的特点,而链表则是删除、插入快,查询慢,那么能不能查询、删除、插入都快呢?散列表就是来解决这个问题的,它使用了数组和链表结合的形式来存储,这个时候你要从线性表的思考方式中跳出来。——弄明白散列表这种数据结构。

通俗的说,HashMap在存储对象想实现插入、删除快速,那么元素就必须按照链表的方式存储,这样在插入和删除的时候才不需要挪动其他元素,只需要改动一两个元素的指针,但是链表查询比较慢,为了查询快速,散列表把一个链表分解成很多小链表,而每一个链表挂在一个数组的元素上面,数组元素是有索引的可以直接定位,不需要遍历,如果想查询一个元素,就首先需要知道它位于哪个数组元素里,定位到一个小链表,然后只遍历这个长度比较小的小链表就可以了,减少了遍历浪费的时间。一个元素应该被放在数组的哪个位置呢——通过hash函数来计算,这时候就需要hashcode了。

hashcode在存储上的使用是这样的,一个对象通过调用它的hashcode()得到自己的hashcode,然后再通过一个散射函数(hash函数)得到一个数组的index,在上一篇文章Java中hashcode方法与equals方法关联关系的直观解释中,我举鸡蛋和篮子的例子从这个方向上看就不是很恰当了,其实m%3是散列函数,而编号才是hashcode,当然里面的道理是一致的。(注意:hashcode和数组index之间也不是一一对应关系,hashcode更不等同于index。)

就目前我所得到的信息,hashcode方法是返回一个代表对象身份信息的整数,已知的作用是为了给散列表(哈希表)使用的,至于有没有其他的作用我不知道,如果您知道其他的作用请在文章后面评论,我会非常感激。我总是觉得hashcode的作用应该还有其他的,为什么呢,因为它被写在了Object方法里面,假如说只是给散列表使用的话,那么完全可以通过一个接口(假设叫Hashcode)来实现,比如你希望让你所定义的类作为key使用,那么你就要implements这个接口,然后实现hashcode方法,并选择性重写Object类里面的equals方法,比如java.lang.String这个类就可以这样做。当然了如果这么设计的话,那么hashMap类的键值就必须规定为Hashcode类型。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值