hashCode and equals in map
问题描述
一道来自Java
官方twitter
的问题。风格很像目前国内各大互联网公司的笔试题。
public class MapEqualsChallenge {public static void main(String[] args) {Map<Stark, String> map = new LinkedHashMap<>();map.put(new Stark("Arya"), "1");map.put(new Stark("Ned"), "2");map.put(new Stark("Sansa"), "3");map.put(new Stark("Bran"), "4");map.put(new Stark("Jaime"), "5");map.forEach((key, value) -> System.out.println(value));}static class Stark {String name;public Stark(String name) {this.name = name;}@Overridepublic boolean equals(Object obj) {return ((Stark) obj).name.length() == this.name.length();}@Overridepublic int hashCode() {return 4000 << 2 * 2000 / 10000;}}
}
挺有意义的一道题,绝对是学习equals
和hashcode
的经典案例,为官方社区点个赞。
分析
Java 集合
这是一个有关Java
集合的关系图,最初觉得这个好复杂,但是现在再去看看,其实也很简单。
Collection
和Map
接口都是我们常用的,这个图有一点问题,在JDK
的源码中,Map
和Collection
毫无关系。
List
:强调数据在集合中的位置。
Set
:强调集合中元素不允许重复。
Map
:强调集合中的元素根据key
来查询。
如果你不明白三者的区别与联系,请看《Head First Java 第二版》557页,书中用图示对三者进行了详细的阐述。
LinkedHashMap
之前研究过HashMap
和ConcurrentHashMap
(线程安全的HashMap
),这个LinkedHashMap
倒是第一次见。
LinkedHashMap
继承自HashMap
,二者区别不大。
存放数据,根据key
计算哈希值,然后根据哈希值计算该元素应当存储在数组中的位置,如果hash
冲突,并且不是一个对象,则用链表处理。
HashMap
实现的是单向链表,LinkedHashMap
实现的是双向链表。
hashCode
这是源码中计算哈希值的方法,先取对象的哈希值,然后再进行相应的处理。
所以再去看put
过程:key
是一个对象,然后LinkedHashMap
会调用key
的hashCode
方法。
map.put(new Stark("Arya"), "1");
我们可能一看这个hashCode
方法就吓蒙了,这怎么算啊?其实我们完全没必要去计算这个表达式,这是个常量表达式,所以不管new
出来多少个对象,哈希值都是一样的。再去调用LinkedHashMap
的hash
方法,返回值也是一样。
@Override
public int hashCode() {return 4000 << 2 * 2000 / 10000;
}
先不去管到底是双向链表还是单向链表,反正哈希值相同,这些个键值对肯定在一个链表上。
map.put(new Stark("Arya"), "1");
执行第一行代码,插入key
为Arya
对象,value
为1
的节点对象。
equals
map.put(new Stark("Ned"), "2");
放入第二个元素,再计算哈希值,发现与第一个节点key
的哈希值相同。
如果两个对象的哈希值相等,则这两个对象有可能相等;如果两个对象的哈希值不相等,那这两个对象肯定不相等。
哈希值相等,然后用equals
方法判断两个对象是否相等。
@Override
public boolean equals(Object obj) {return ((Stark) obj).name.length() == this.name.length();
}
重写过的equals
是根据对象名字的长度来判等的,如果两个对象名字长度相等,那就认为是同一对象。
Arya
与Ned
长度不相等,所以LinkedHashMap
认为这是两个对象,再去新建一个Node
,指过去。
注意:这里有一个插入的位置问题,到底是在链表头部插新节点还是在尾部插新节点?据说面试官还考过?
答案是:在Java8
之前,是在头部插入节点;在Java8
中,是在尾部插入节点。
文章链接:HashMap到底是插入链表头部还是尾部
map.put(new Stark("Sansa"), "3");
又来一个,哈希值相等,名字长度为5
,没有一样的key
,再插一个新节点。
覆盖
map.put(new Stark("Bran"), "4");
又来一个,哈希值相等,长度为4
,与Arya 1
是相等的,直接将原节点的值覆盖。由1
修改为4
。
map.put(new Stark("Jaime"), "5");
第五个,哈希值相等,长度为5
,与Sansa 3
相等,覆盖,由3
修改为5
。
结果
分析了一大堆,切换到IDE
中运行,与预期结果一致。
总结
学然后知不足,教然后知困!
之前觉得自己对HashMap
还是听明白的,但当自己去画各种示意图时,发现还有很多细节去需要学习。
hashCode and equals in map相关推荐
- hashcode的作用_看似简单的hashCode和equals面试题,竟然有这么多坑!
hashCode()方法和equals()区别与联系这到面试题,看似简单,根据以往面试星友的情况来说,绝大部分人都不能很好的回答出来,要么没有逻辑,想到一句就说一句,要么抓不住重点,答非所问.从这个很 ...
- HashMap存自定义对象为什么要重写 hashcode 和 equals 方法?
HashMap的k放过自定义对象么? 当我们把自定义对象存入HashMap中时,如果不重写hashcode和equals这两个方法,会得不到预期的结果. class Key{private Integ ...
- (转)从一道面试题彻底搞懂hashCode与equals的作用与区别及应当注意的细节
背景:学习java的基础知识,每次回顾,总会有不同的认识.该文系转载 最近去面试了几家公司,被问到hashCode的作用,虽然回答出来了,但是自己还是对hashCode和equals的作用一知半解的, ...
- 【面试题】hashCode() 和 equals() 之间的关系
前言 关于 hashCode 和 equals 的处理,遵循如下规则: 只要重写 equals,就必须重写 hashCode 因为 Set 存储的是不重复的对象,依据 hashCode 和 equal ...
- hashCode() 和equals() 区别和作用
HashSet和HashMap一直都是JDK中最常用的两个类,HashSet要求不能存储相同的对象,HashMap要求不能存储相同的键. 那么Java运行时环境是如何判断HashSet中相同对象.Ha ...
- hashCode()、equals()以及compareTo()方法的理解
原文出自:http://blog.sina.com.cn/s/blog_50d936c40100nvzz.html hashCode().equals()以及compareTo()方法的理解 转载▼ ...
- Lombok的@Data生成的hashCode和equals方法坑
一.场景复现 创建两个lombok的@Data注解的类Pig实例,放进HashMap当key,map里面的数据居然被覆盖了. package com.mk;import lombok.Data; @D ...
- 【Java开发规范】hashCode 和 equals 的处理规则
(1)只要覆写 equals,就必须覆写 hashCode. 说明:因为 Set 存储的是不重复的对象,依据 hashCode 和 equals 进行判断,所以 Set 存储的对象必须覆写这两种方法. ...
- 深入探究Java中hashCode()和equals()的关系
目录 一.基础:hashCode() 和 equals() 简介 equals() hashCode() 二. 漫谈:初识 hashCode() 与 equals() 之间的关系 三. 解密:深入理解 ...
最新文章
- 基于用户画像 《列变行》 特征打标显示
- 蚂蚁金服蓝绿发布实践
- Chrome V8系列--浅析Chrome V8引擎中的垃圾回收机制和内存泄露优化策略
- asp.net 读取excel文件
- oracle join详解,inner join和left join之间的区别详解
- [蓝桥杯][2019年第十届真题]修改数组(并查集)
- datagridview取消默认选中_winform datagridview中的 combobox如何选中默认值?
- attention机制中的注意力图怎么画_注意力机制 | 图卷积多跳注意力机制 | Direct multihop Attention based GNN...
- STM32“隐藏的定时器”-DWT
- OS X 终端修改备忘录
- subst 的使用 创建虚拟盘符
- 用本地计算机做服务器提供外网访问:花生壳+tomcat
- 麦咭萌app送智伴机器人_国内儿童陪伴机器人品牌盘点
- 状态压缩dp(规律)
- Sun工作站技术文档
- storyboard(故事版)新手教程 图文详解 1.创建一个无约束的导航栏加选项卡(tabbar)故事版
- html提取excel指定单元格数据,怎样从很多的表格中提取指定单元格数据
- 经典算法电话号码的字母组合
- [Excel]如何去除恼人的外部链接
- iOS企业包下载安装
热门文章
- Spring安全示例UserDetailsS​​ervice
- 转:标准C++中的string类的用法总结
- C++开发需要掌握哪些技能?
- Mac 电脑如何卸载 node
- input文本框不可编辑的方法
- 面向对象和面向过程思想 oc
- Event Logging 技术简介
- 【DP】LeetCode 64. Minimum Path Sum
- 【Hard 递归 动态规划 回文串15】LeetCode 730. Count Different Palindromic Subsequences
- Leetcode 742.二叉树最近的叶子结点