【Java深入浅出】Map篇
【摘要】 本文深入浅出地介绍了Java中的Map相关类型的方方面面。用问答、代码的形式针对易混淆、易搞错的场景进行了针对性阐示。
Java中关键的Map有哪些类型?它们之间的继承关系是怎么样的?
Java中的主要map以及继承关系图如下:
这么多List、Set,他们之间肯定有很多相似跟区别,都有哪些关键的关注点呢?
它们的一些关键特点、要素汇总表如下:
在对象被作为HashMap或HashSet的key时,重写equals方法跟hashcode方法的注意事项。
上面代码的结果是null。hashMap.get(key2)获取不到k1作为key在map中的value。
解析:由于Key没有重写equals方法、hashCode方法,默认使用了Object中这两个方法的定义。只有当两个对象地址相同时,equals才返回为true,hashCode返回值也才相同。(Object.hashCode方法返回对象地址)所以在这里,key1、key2逻辑上也被认为不相等,当然无法通过key2获取key1的关联value。
要想让id相同的key1、key2被逻辑认为是相同的,则必须要覆盖equals方法。同时也需要覆盖hashCode方法。需满足如下约束:
- 规则1:当两个对象equals为true时,hashCode必须相同。
- 建议1:当两个对象equals为false时,hashCode建议不同,但也可以相同。(此时不同的话散列效果好、性能高)
- 推论1:两个对象hashCode相同时,两者equals结果不一定为true。
- 推论2:两个对象hashCode不同时,两者equals结果一定为false。
我们重点理解下规则1,hashMap的get(key2)方法的逻辑是,先根据key2的hashCode计算出应该到哪个桶里去找,再用key2的equals方法与桶里链表上的元素依次比较找到相同的。如果两个对象逻辑相同(equals结果为true),hashCode值不同的话,就有可能定位不到正确的桶(hashCode值%容量大小=桶的序号),导致找不到,返回null。
推论2是规则1的逆否命题,所以也成立(若a则b命题成立 <==> 若非b则非a命题成立)。
HashMap 的长度为什么是2的幂次方?
一个元素究竟该从HashMap的哪个桶里存取,是通过计算hashcode值再取余计算得来的。当取余操作的除数是2的幂次方时有一个特性:取余操作 <==> 与其除数-1 的与(&)操作。机器执行二进制的&操作的效率是要远远大于取余(%)的运算效率的。
length 是2的 n 次方时:hashcode%length == hashcode&(length-1)
JDK1.7 和1.8 之间, hashMap做了什么改进?
答:1.7的哈希即使冲突严重,也只会在一个点上形成的链表不断链接更多的元素,别无他法。因此1.8做了改进,如果那个点的链表长度超过TREEIFY_THRESHOLD,则会转为红黑树。提升了效率、安全性(防止恶意构造大量hash冲突的元素插入map操作内存耗尽)。
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)