原文:https://www.liaoxuefeng.com/article/1256136507802816

正确使用Map,只需要正确实现hashCode()equals()就行了吗?

恐怕还不行。

确切地说,如果使用的是HashMap,那么只需要正确实现hashCode()equals()就够了。

但是,如果换成TreeMap,正确实现hashCode()equals(),结果并不一定正确。

代码胜于雄辩。先看作为key的class定义:

class Student implements Comparable<Student> {
final String name;
final int score; public Student(String name, int score) {
this.name = name;
this.score = score;
} @Override
public int hashCode() {
return Objects.hash(name, score);
} @Override
public boolean equals(Object obj) {
if (obj instanceof Student) {
Student o = (Student) obj;
return Objects.equals(this.name, o.name) && this.score == o.score;
}
return false;
} @Override
public int compareTo(Student o) {
return this.score < o.score ? -1 : 1;
}
}

先用HashMap测试:

Map<Student, Integer> map = new HashMap<>();
map.put(new Student("Michael", 99), 99);
map.put(new Student("Bob", 88), 88);
map.put(new Student("Alice", 77), 77);
System.out.println(map.get(new Student("Michael", 99)));
System.out.println(map.get(new Student("Bob", 88)));
System.out.println(map.get(new Student("Alice", 77)));

输出为998877,一切正常。

HashMap改为TreeMap再测试:

Map<Student, Integer> map = new TreeMap<>();

输出为nullnullnull

怎么肥四?

说好的接口不变,实现类随便换现在不管用了?难道是JDK的bug?

遇到这种诡异的问题,首先在心里默念三遍:

  • JDK没有bug。
  • JDK没有bug。
  • JDK没有bug。

然后开始从自己的代码找原因。

先打开JDK的TreeMap文档,注意到这句话:

This is so because the Map interface is defined in terms of the equals operation, but a sorted map performs all key comparisons using its compareTo (or compare) method

意思是,Map接口定义了使用equals()判定key是否相等,但是SortedMap却使用compareTo()来判断key是否相等,而TreeMap是一种SortedMap

所以,问题出在compareTo()方法上:

@Override
public int compareTo(Student o) {
return this.score < o.score ? -1 : 1;
}

上面这个定义,用来排序是没问题的,但是,没法判断相等。TreeMap根据key.compareTo(anther)==0判断是否相等,而不是equals()

所以,解决问题的关键是正确实现compareTo(),该相等的时候,必须返回0

@Override
public int compareTo(Student o) {
int n = Integer.compare(this.score, o.score);
return n != 0 ? n : this.name.compareTo(o.name);
}

修正代码后,再次运行,一切正常。

Java Map的正确使用方式的更多相关文章

  1. Java ThreadPool的正确打开方式花钱的年华 | 江南白衣(5星推荐)

    线程池应对于突然增大.来不及处理的请求,无非两种应对方式: 将未完成的请求放在队列里等待 临时增加处理线程,等高峰回落后再结束临时线程 JDK的Executors.newFixedPool() 和ne ...

  2. map的正确删除方式

    遍历删除map元素的正确方式是 for(itor = maptemplate.begin; itor != maptemplate.end(); ) {      if(neederase)     ...

  3. Java map双括号初始化方式的问题

    关于Java双括号的初始化凡是确实很方便,特别是在常量文件中,无可替代.如下所示: Map map = new HashMap() { { put("Name", "Un ...

  4. Java流的正确关闭方式

    因为流是无论如何一定要关闭的,所以要写在finally里.如下: BufferedReader reader = null; try { reader = (BufferedReader) getRe ...

  5. Java遍历Map的3种方式

    package test; import java.util.Collection; import java.util.HashMap; import java.util.Map; import ja ...

  6. Redis实现分布式锁的正确使用方式(java版本)

    Redis实现分布式锁的正确使用方式(java版本) 本文使用第三方开源组件Jedis实现Redis客户端,且只考虑Redis服务端单机部署的场景. 分布式锁一般有三种实现方式: 1. 数据库乐观锁: ...

  7. java 遍历Map的四种方式

      java 遍历Map的四种方式 CreationTime--2018年7月16日16点15分 Author:Marydon 一.迭代key&value 第一种方式:迭代entrySet 1 ...

  8. java map遍历方式及效率

    本文转载自Java Map遍历方式的选择. 只给出遍历方式及结论.测试数据可以去原文看. 如果你使用HashMap 同时遍历key和value时,keySet与entrySet方法的性能差异取决于ke ...

  9. Java Collection - 遍历map的几种方式

    作者:zhaoguhong(赵孤鸿) 出处:http://www.cnblogs.com/zhaoguhong/ 本文版权归作者和博客园共有,转载请注明出处 ---------------- 总结 如 ...

随机推荐

  1. C#程序打包安装部署之添加注册表项(转)

    今天为大家整理了一些怎样去做程序安装包的具体文档,这些文档并不能确保每个人在做安装包的时候都能正确去生成和运行,但是这些文档的指导作用对于需要的朋友来说还是很有必要的,在实际产品的安装部署过程中可能有 ...

  2. 安装tensorflow2.0

    pip install tensorflow==2.0.0 -i https://pypi.tuna.tsinghua.edu.cn/simple import tensorflow as tfpri ...

  3. consul异地多数据中心以及集群部署方案

    consul异地多数据中心以及集群部署方案目的实现consul 异地多数据中心环境部署,使得一个数据中心的服务可以从另一个数据中心的consul获取已注册的服务地址 环境准备两台 linux服务器,外 ...

  4. Survey of single-target visual tracking methods based on online learning 翻译

    基于在线学习的单目标跟踪算法调研 摘要 视觉跟踪在计算机视觉和机器人学领域是一个流行和有挑战的话题.由于多种场景下出现的目标外貌和复杂环境变量的改变,先进的跟踪框架就有必要采用在线学习的原理.本论文简 ...

  5. centos php7.1 redis4.0.9 安装扩展phpredis

    1.扩展列表 https://github.com/phpredis/phpredis/releases [root@VM_27_0_centos server]# ls data lib.pl my ...

  6. 在ensp中RSTP基础设置

    为什么我们要有rstp? rstp就是stp的加强版 实验模拟内容 搭建拓扑 相关参数(实验的时候看看自己的mac地址可能与我的并不同) 我们开始配置RSTP基本功能,由于交换机默认开启MSTP,所有 ...

  7. 【LeetCode】三数之和【排序,固定一个数,然后双指针寻找另外两个数】

    给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组. 注意:答案中不可以包含重复的三元组. ...

  8. 【转帖】国产PCIe SSD主控芯片获得中国芯大奖 3500MB/s读取

    国产PCIe SSD主控芯片获得中国芯大奖 3500MB/s读取 https://www.cnbeta.com/articles/tech/906033.htm 国产主控 在日前的2019“中国芯”集 ...

  9. python大道——博客目录

      python基础 第一章 计算机基础 计算机基础 第二章 python基础语法 python入门 第三章 基础数据类型和文件操作 整型.布尔.字符串 列表.字典.集合 公共功能.小数据池 hash ...

  10. 关于TI公司DSP工程调用DELAY_US()进入非法中断问题的解决

    最近笔者在调试一个DSP程序时,发现在ad外设初始化时无法正常执行,单步检查,发现当执行到调用 DELAY_US(1000);语句时,就跳入非法. 进一步追查,DELAY_US()是宏定义函数,在笔者 ...