需要重写hashCode()和equals()方法才可以实现自定义键在HashMap中的查找。

public class PhoneNumber
{
private int prefix; //区号
private int phoneNumber; //电话号 public PhoneNumber(int prefix, int phoneNumber)
{
this.prefix = prefix;
this.phoneNumber = phoneNumber;
}
}
import java.util.HashMap;

public class Test1
{
public static void main(String[] args)
{
HashMap<PhoneNumber, String> map = new HashMap<>(); map.put(new PhoneNumber(027, 12345678), "zhangsan");
map.put(new PhoneNumber(027, 22222222), "lisi");
map.put(new PhoneNumber(027, 33333333), "wangwu");
map.put(new PhoneNumber(027, 33333333), "abc"); System.out.println(map.toString()); System.out.println(map.get(new PhoneNumber(027, 12345678)));
System.out.println(map.get(new PhoneNumber(027, 22222222)));
System.out.println(map.get(new PhoneNumber(027, 33333333)));
}
}

运行结果为:

{package1.PhoneNumber@74a14482=zhangsan, package1.PhoneNumber@677327b6=wangwu, package1.PhoneNumber@1540e19d=lisi, package1.PhoneNumber@14ae5a5=abc}

null

null

null

从中我们可以看到出现了两个问题:

  • new PhoneNumber(027, 33333333)这个键被添加了两次,但是在HashMap中wangwu和abc同时存在了
  • 使用get方法取得的值均为null

正确的方法就是直接对PhoneNumber类进行修改,覆盖equals和hashCode方法,修改后的PhoneNumber类如下:

public class PhoneNumber
{
private int prefix; //区号
private int phoneNumber; //电话号 public PhoneNumber(int prefix, int phoneNumber)
{
this.prefix = prefix;
this.phoneNumber = phoneNumber;
} @Override
public boolean equals(Object o)
{
if(this == o)
{
return true;
}
if(!(o instanceof PhoneNumber))
{
return false;
}
PhoneNumber pn = (PhoneNumber)o;
return pn.prefix == prefix && pn.phoneNumber == phoneNumber;
} @Override
public int hashCode()
{
int result = 17;
result = 31 * result + prefix;
result = 31 * result + phoneNumber;
return result;
}
}

重新执行上述函数,结果为:

{package1.PhoneNumber@1fce2ef=abc, package1.PhoneNumber@bca3e8=zhangsan, package1.PhoneNumber@1535828=lisi}

zhangsan

lisi

abc

可以看到,之前出的错误都被改正了

在HashMap中,查找key的比较顺序为:

  1. 计算对象的HashCode,看在表中是否存在
  2. 检查HashCode位置中的对象是否与当前对象相等

以上使用计算HashCode的方法在effective java第九点中提到:

  • 对于对象中每个关键域f,为该域计算int类型的散列码c,result = 31 * result + c

Java用自定义的类型作为HashMap的key的更多相关文章

  1. 一个关于自定义类型作为HashMap的key的问题

    在之前的项目需要用到以自定义类型作为HashMap的key,遇到一个问题:如果修改了已经存储在HashMap中的实例,会发生什么情况呢?用一段代码来试验: import java.util.HashM ...

  2. java自定义类型 作为HashMap中的Key值 (Pair<V,K>为例)

    由于是自定义类型,所以HashMap中的equals()方法和hashCode()方法都需要自定义覆盖. 不然内容相同的对象对应的hashCode会不同,无法发挥算法的正常功能,覆盖equals方法, ...

  3. JAVA - 如果hashMap的key是一个自定义的类,怎么办?

    JAVA - 如果hashMap的key是一个自定义的类,怎么办? 使用HashMap,如果key是自定义的类,就必须重写hashcode()和equals().

  4. 【java】学习路径26-泛型,集合使用自定义的类型

    接着上一节的内容,上一节我们使用到了ArrayList.Vector.LinkedList三个集合类型. 但是目前我们有一个问题:如果集合中存储的是Integer类型的数据(int的引用类型),那我们 ...

  5. java容器类2:Map及HashMap深入解读

    Java的编程过程中经常会和Map打交道,现在我们来一起了解一下Map的底层实现,其中的思想结构对我们平时接口设计和编程也有一定借鉴作用.(以下接口分析都是以jdk1.8源码为参考依据) 1. Map ...

  6. Java集合类源码解析:HashMap (基于JDK1.8)

    目录 前言 HashMap的数据结构 深入源码 两个参数 成员变量 四个构造方法 插入数据的方法:put() 哈希函数:hash() 动态扩容:resize() 节点树化.红黑树的拆分 节点树化 红黑 ...

  7. Java编程的逻辑 (40) - 剖析HashMap

    本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...

  8. 全面解读Java中的枚举类型enum的使用

    这篇文章主要介绍了Java中的枚举类型enum的使用,开始之前先讲解了枚举的用处,然后还举了枚举在操作数据库时的实例,需要的朋友可以参考下 关于枚举 大多数地方写的枚举都是给一个枚举然后例子就开始sw ...

  9. Java中的集合类型体系(一)

    Java中的集合类型体系(一) 提问:为什么需要集合? 通常情况下,程序需要根据运行时才知道创建了多少对象.若非程序运行时,而在开发阶段,我们并不知道创建了多少对象,甚至不知道对象的准确类型,为了满足 ...

随机推荐

  1. opencv图像特征检测之斑点检测

    前面说过,图像特征点检测包括角点和斑点,今天来说说斑点,斑点是指二维图像中和周围颜色有颜色差异和灰度差异的区域,因为斑点代表的是一个区域,所以其相对于单纯的角点,具有更好的稳定性和更好的抗干扰能力. ...

  2. X-002 Exyson4412芯片启动过程分析

    移植u-boot到FriendlyARM Tiny4412开发板上,首先我们需要对Samsung Exyson4412芯片的启动方式.系统时钟初始化.串口初始化.内存初始化以及开发板的内存地址空间分配 ...

  3. webstorm 激活码

    WebStorm 2016 最新版激活(activation code方式) 注册时,在打开的License Activation窗口中选择“activation code”,在输入框输入下面的注册码 ...

  4. 在IOS中使用DES算法对Sqlite数据库进行内容加密存储并读取解密

    在IOS中使用DES算法对Sqlite 数据库进行内容加密存储并读取解密 涉及知识点: 1.DES加密算法: 2.OC对Sqlite数据库的读写: 3.IOS APP文件存储的两种方式及读取方式. 以 ...

  5. UVa 495 - Fibonacci Freeze

    题目大意:计算斐波那契数列的第n项. 由于结果会很大,要用到大数.开始本来想节省空间的,就没用数组保存,结果超时了... import java.io.*; import java.util.*; i ...

  6. Linux之文件权限属性设置

    文件权限属性设置 1.chown命令 chrep命令 chown命令改变某个文件或目录的所有者和所属的组,该命令可以向某个用户授权,使该用户变成指定文件的所有者或者改变文件所属的组. 用户可以是用户或 ...

  7. Python twisted article

    学习python twisted 的好文章 An Introduction to Asynchronous Programming and Twisted Reference: http://kron ...

  8. 有限状态机(Finite-state machine)

    var menu = { // 当前状态 currentState: 'hide', // 绑定事件 initialize: function() { var self = this; self.on ...

  9. PHP 中 static 和 self 的区别

    使用 self:: 或者 __CLASS__ 对当前类的静态引用,取决于定义当前方法所在的类: 使用 static:: 不再被解析为定义当前方法所在的类,而是在实际运行时计算的.也可以称之为" ...

  10. 负载均衡探测器lbd

    负载均衡探测器lbd   大型网站为了解决海量访问问题,往往采用负载均衡技术,将用户的访问分配到不同的服务器上.网站的负载均衡可以从DNS和HTTP两个环节进行实施.在进行Web渗透测试的时候,需要先 ...