问题描述

一道来自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;}}
}

挺有意义的一道题,绝对是学习equalshashcode的经典案例,为官方社区点个赞。

分析

Java 集合

这是一个有关Java集合的关系图,最初觉得这个好复杂,但是现在再去看看,其实也很简单。

CollectionMap接口都是我们常用的,这个图有一点问题,JDK的源码中,MapCollection毫无关系

List:强调数据在集合中的位置。

Set:强调集合中元素不允许重复。

Map:强调集合中的元素根据key来查询。

如果你不明白三者的区别与联系,请看《Head First Java 第二版》557页,书中用图示对三者进行了详细的阐述。

LinkedHashMap

之前研究过HashMapConcurrentHashMap(线程安全的HashMap),这个LinkedHashMap倒是第一次见。

LinkedHashMap继承自HashMap,二者区别不大。

存放数据,根据key计算哈希值,然后根据哈希值计算该元素应当存储在数组中的位置,如果hash冲突,并且不是一个对象,则用链表处理。

HashMap实现的是单向链表,LinkedHashMap实现的是双向链表。

hashCode

这是源码中计算哈希值的方法,先取对象的哈希值,然后再进行相应的处理。

所以再去看put过程:key是一个对象,然后LinkedHashMap会调用keyhashCode方法。

map.put(new Stark("Arya"), "1");

我们可能一看这个hashCode方法就吓蒙了,这怎么算啊?其实我们完全没必要去计算这个表达式,这是个常量表达式,所以不管new出来多少个对象,哈希值都是一样的。再去调用LinkedHashMaphash方法,返回值也是一样。

@Override
public int hashCode() {return 4000 << 2 * 2000 / 10000;
}

先不去管到底是双向链表还是单向链表,反正哈希值相同,这些个键值对肯定在一个链表上。

map.put(new Stark("Arya"), "1");

执行第一行代码,插入keyArya对象,value1的节点对象。

equals

map.put(new Stark("Ned"), "2");

放入第二个元素,再计算哈希值,发现与第一个节点key的哈希值相同。

如果两个对象的哈希值相等,则这两个对象有可能相等;如果两个对象的哈希值不相等,那这两个对象肯定不相等。

哈希值相等,然后用equals方法判断两个对象是否相等。

@Override
public boolean equals(Object obj) {return ((Stark) obj).name.length() == this.name.length();
}

重写过的equals是根据对象名字的长度来判等的,如果两个对象名字长度相等,那就认为是同一对象。

AryaNed长度不相等,所以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相关推荐

  1. hashcode的作用_看似简单的hashCode和equals面试题,竟然有这么多坑!

    hashCode()方法和equals()区别与联系这到面试题,看似简单,根据以往面试星友的情况来说,绝大部分人都不能很好的回答出来,要么没有逻辑,想到一句就说一句,要么抓不住重点,答非所问.从这个很 ...

  2. HashMap存自定义对象为什么要重写 hashcode 和 equals 方法?

    HashMap的k放过自定义对象么? 当我们把自定义对象存入HashMap中时,如果不重写hashcode和equals这两个方法,会得不到预期的结果. class Key{private Integ ...

  3. (转)从一道面试题彻底搞懂hashCode与equals的作用与区别及应当注意的细节

    背景:学习java的基础知识,每次回顾,总会有不同的认识.该文系转载 最近去面试了几家公司,被问到hashCode的作用,虽然回答出来了,但是自己还是对hashCode和equals的作用一知半解的, ...

  4. 【面试题】hashCode() 和 equals() 之间的关系

    前言 关于 hashCode 和 equals 的处理,遵循如下规则: 只要重写 equals,就必须重写 hashCode 因为 Set 存储的是不重复的对象,依据 hashCode 和 equal ...

  5. hashCode() 和equals() 区别和作用

    HashSet和HashMap一直都是JDK中最常用的两个类,HashSet要求不能存储相同的对象,HashMap要求不能存储相同的键. 那么Java运行时环境是如何判断HashSet中相同对象.Ha ...

  6. hashCode()、equals()以及compareTo()方法的理解

    原文出自:http://blog.sina.com.cn/s/blog_50d936c40100nvzz.html hashCode().equals()以及compareTo()方法的理解 转载▼ ...

  7. Lombok的@Data生成的hashCode和equals方法坑

    一.场景复现 创建两个lombok的@Data注解的类Pig实例,放进HashMap当key,map里面的数据居然被覆盖了. package com.mk;import lombok.Data; @D ...

  8. 【Java开发规范】hashCode 和 equals 的处理规则

    (1)只要覆写 equals,就必须覆写 hashCode. 说明:因为 Set 存储的是不重复的对象,依据 hashCode 和 equals 进行判断,所以 Set 存储的对象必须覆写这两种方法. ...

  9. 深入探究Java中hashCode()和equals()的关系

    目录 一.基础:hashCode() 和 equals() 简介 equals() hashCode() 二. 漫谈:初识 hashCode() 与 equals() 之间的关系 三. 解密:深入理解 ...

最新文章

  1. 基于用户画像 《列变行》 特征打标显示
  2. 蚂蚁金服蓝绿发布实践
  3. Chrome V8系列--浅析Chrome V8引擎中的垃圾回收机制和内存泄露优化策略
  4. asp.net 读取excel文件
  5. oracle join详解,inner join和left join之间的区别详解
  6. [蓝桥杯][2019年第十届真题]修改数组(并查集)
  7. datagridview取消默认选中_winform datagridview中的 combobox如何选中默认值?
  8. attention机制中的注意力图怎么画_注意力机制 | 图卷积多跳注意力机制 | Direct multihop Attention based GNN...
  9. STM32“隐藏的定时器”-DWT
  10. OS X 终端修改备忘录
  11. subst 的使用 创建虚拟盘符
  12. 用本地计算机做服务器提供外网访问:花生壳+tomcat
  13. 麦咭萌app送智伴机器人_国内儿童陪伴机器人品牌盘点
  14. 状态压缩dp(规律)
  15. Sun工作站技术文档
  16. storyboard(故事版)新手教程 图文详解 1.创建一个无约束的导航栏加选项卡(tabbar)故事版
  17. html提取excel指定单元格数据,怎样从很多的表格中提取指定单元格数据
  18. 经典算法电话号码的字母组合
  19. [Excel]如何去除恼人的外部链接
  20. iOS企业包下载安装

热门文章

  1. Spring安全示例UserDetailsS​​ervice
  2. 转:标准C++中的string类的用法总结
  3. C++开发需要掌握哪些技能?
  4. Mac 电脑如何卸载 node
  5. input文本框不可编辑的方法
  6. 面向对象和面向过程思想 oc
  7. Event Logging 技术简介
  8. 【DP】LeetCode 64. Minimum Path Sum
  9. 【Hard 递归 动态规划 回文串15】LeetCode 730. Count Different Palindromic Subsequences
  10. Leetcode 742.二叉树最近的叶子结点