J2SE知识点摘记(二十四)
覆写hashCode()
在明白了HashMap具有哪些功能,以及实现原理后,了解如何写一个hashCode()方法就更有意义了。当然,在HashMap中存取一个键值对涉及到的另外一个方法为equals (),因为该方法的覆写在高级特性已经讲解了。这里就不做过多的描述。
设计hashCode()时最重要的因素就是:无论何时,对同一个对象调用hashCode()都应该生成同样的值。如果在将一个对象用put()方法添加进HashMap时产生一个hashCode()值,而用get()取出时却产生了另外一个hashCode()值,那么就无法重新取得该对象了。所以,如果你的hashCode()方法依赖于对象中易变的数据,那用户就要小心了,因为此数据发生变化时,hashCode()就会产生一个不同的hash码,相当于产生了一个不同的“键”。
此外,也不应该使hashCode()依赖于具有唯一性的对象信息,尤其是使用this的值,这只能产生很糟糕的hashCode()。因为这样做无法生成一个新的“键”,使之与put()种原始的“键值对”中的“键”相同。例如,如果我们不覆写Object的hashCode()方法,那么调用该方法的时候,就会调用Object的hashCode()方法的默认实现。Object的hashCode()方法,返回的是当前对象的内存地址。下次如果我们需要取一个一样的“键”对应的键值对的时候,我们就无法得到一样的hashCode值了。因为我们后来创建的“键”对象已经不是存入HashMap中的那个内存地址的对象了。
我们看一个简单的例子,就能更加清楚的理解上面的意思。假定我们写了一个类:Person (人),我们判断一个对象“人”是否指向同一个人,只要知道这个人的身份证号一直就可以了。
先看我们没有实现hashCode的情况:
package c08.hashEx;
import java.util.*;
//身份证类
class Code{
final int id;//身份证号码已经确认,不能改变
Code(int i){
id=i;
}
//身份号号码相同,则身份证相同
public boolean equals(Object anObject) {
if (anObject instanceof Code){
Code other=(Code) anObject;
return this.id==other.id;
}
return false;
}
public String toString() {
return "身份证:"+id;
}
}
//人员信息类
class Person {
Code id;// 身份证
String name;// 姓名
public Person(String name, Code id) {
this.id=id;
this.name=name;
}
//如果身份证号相同,就表示两个人是同一个人
public boolean equals(Object anObject) {
if (anObject instanceof Person){
Person other=(Person) anObject;
return this.id.equals(other.id);
}
return false;
}
public String toString() {
return "姓名:"+name+" 身份证:"+id.id+"\n";
}
}
public class HashCodeEx {
public static void main(String[] args) {
HashMap map=new HashMap();
Person p1=new Person("张三",new Code(123));
map.put(p1.id,p1);//我们根据身份证来作为key值存放到Map中
Person p2=new Person("李四",new Code(456));
map.put(p2.id,p2);
Person p3=new Person("王二",new Code(789));
map.put(p3.id,p3);
System.out.println("HashMap 中存放的人员信息:\n"+map);
// 张三 改名为:张山 但是还是同一个人。
Person p4=new Person("张山",new Code(123));
map.put(p4.id,p4);
System.out.println("张三改名后 HashMap 中存放的人员信息:\n"+map);
//查找身份证为:123 的人员信息
System.out.println("查找身份证为:123 的人员信息:"+map.get(new Code(123)));
}
}
运行结果为:
HashMap 中存放的人员信息:
{身份证:456=姓名:李四 身份证:456
, 身份证:123=姓名:张三 身份证:123
, 身份证:789=姓名:王二 身份证:789
}
张三改名后 HashMap 中存放的人员信息:
{身份证:456=姓名:李四 身份证:456
, 身份证:123=姓名:张三 身份证:123
, 身份证:123=姓名:张山 身份证:123
, 身份证:789=姓名:王二 身份证:789
}
查找身份证为:123 的人员信息:null
上面的例子的演示的是,我们在一个HashMap中存放了一些人员的信息。并以这些人员的身份证最为人员的“键”。当有的人员的姓名修改了的情况下,我们需要更新这个HashMap。同时假如我们知道某个身份证号,想了解这个身份证号对应的人员信息如何,我们也可以根据这个身份证号在HashMap中得到对应的信息。
而例子的输出结果表示,我们所做的更新和查找操作都失败了。失败的原因就是我们的身份证类:Code 没有覆写hashCode()方法。这个时候,当查找一样的身份证号码的键值对的时候,使用的是默认的对象的内存地址来进行定位。这样,后面的所有的身份证号对象new Code(123) 产生的hashCode()值都是不一样的。所以导致操作失败。
下面,我们给Code类加上hashCode()方法,然后再运行一下程序看看:
//身份证类
class Code{
final int id;//身份证号码已经确认,不能改变
Code(int i){
id=i;
}
//身份号号码相同,则身份证相同
public boolean equals(Object anObject) {
if (anObject instanceof Code){
Code other=(Code) anObject;
return this.id==other.id;
}
return false;
}
public String toString() {
return "身份证:"+id;
}
//覆写hashCode方法,并使用身份证号作为hash值
public int hashCode(){
return id;
}
}
再次执行上面的HashCodeEx 的结果就为:
HashMap 中存放的人员信息:
{身份证:456=姓名:李四 身份证:456
, 身份证:789=姓名:王二 身份证:789
, 身份证:123=姓名:张三 身份证:123
}
张三改名后 HashMap 中存放的人员信息:
{身份证:456=姓名:李四 身份证:456
, 身份证:789=姓名:王二 身份证:789
, 身份证:123=姓名:张山 身份证:123
}
查找身份证为:123 的人员信息:姓名:张山 身份证:123
这个时候,我们发现。我们想要做的更新和查找操作都成功了。
对于Map部分的使用和实现,主要就是需要注意存放“键值对”中的对象的equals()方法和hashCode()方法的覆写。如果需要使用到排序的话,那么还需要实现Comparable 接口中的compareTo() 方法。我们需要注意Map中的“键”是不能重复的,而是否重复的判断,是通过调用“键”对象的equals()方法来决定的。而在HashMap中查找和存取“键值对”是同时使用hashCode()方法和equals()方法来决定的。
J2SE知识点摘记(二十四)的更多相关文章
- J2SE知识点摘记(二十六)
为了用“集合框架”的额外部分把排序支持添加到 Java 2 SDK,版本 1.2,核心 Java 库作了许多更改.像 String 和 Integer 类如今实现 Comparable 接口以提供自然 ...
- J2SE知识点摘记(二十五)
Set 1.5.1 概述 Java 中的Set和正好和数学上直观的集(set)的概念是相同的.Set最大的特性就是不允许在其中存放的元素是重复的.根据这个特点,我们就可以使用Set 这个 ...
- J2SE知识点摘记(二十二)
Map 1.4.1 概述 数学中的映射关系在Java中就是通过Map来实现的.它表示,里面存储的元素是一个对(pair),我们通过一个对象,可以在这个映射关系中找到另外一个和这个对象相关 ...
- J2SE知识点摘记(二十)
List 1.3.1 概述 前面我们讲述的Collection接口实际上并没有直接的实现类.而List是容器的一种,表示列表的意思.当我们不知道存储的数据有多少的情况,我们就可以使用Li ...
- J2SE知识点摘记(二十三)
我们简单介绍一下这个接口: 1.4.3 Comparable 接口 在 java.lang 包中,Comparable 接口适用于一个类有自然顺序的时候.假定对象集合是同一类型,该接口允 ...
- J2SE知识点摘记(二)
1. 对象的声明 "类名 对象名 = new 类名();"例子:Person P;//先声明一个Person类的对象p p=new Person();//用new关键字实例化 ...
- J2SE知识点摘记(二十一)
实现原理 前面已经提了一下Collection的实现基础都是基于数组的.下面我们就已ArrayList 为例,简单分析一下ArrayList 列表的实现方式.首先,先看下它的构造函数. 下列表格是在S ...
- 小小知识点(二十四)什么是5G
转自 https://www.ifanr.com/1149419 一个简单且神奇的公式 今天的故事,从一个公式开始讲起.这是一个既简单又神奇的公式.说它简单,是因为它一共只有 3 个字母.而说它神奇, ...
- JAVA之旅(二十四)——I/O流,字符流,FileWriter,IOException,文件续写,FileReader,小练习
JAVA之旅(二十四)--I/O流,字符流,FileWriter,IOException,文件续写,FileReader,小练习 JAVA之旅林林总总也是写了二十多篇了,我们今天终于是接触到了I/O了 ...
随机推荐
- yum php56
美国时间2014年11月13日,PHP开发团队,在「PHP 5.6.3 is available|PHP: Hypertext Preprocessor」上公布了PHP5.6系的最新版本「PHP 5. ...
- sublime前端编辑器入门与个人使用经验分享
Sublime Text(以下简称sublime)是一款很好用的代码编辑器,小巧且很灵敏,几乎可以编写大部分主流的计算机语言代码,更是堪称前端代码编辑神器. 你百度一下会发现许多sublime的安装和 ...
- 关于PHPExcel
在学PHPExcel的时候,在网上查了很多资料,花了很多时间,下面是我想要分享给大家的,我找到的并进行了一定修改的亲身实践成功的资料,希望大家对大家有所帮助. 首先,需要下载PhpExcel资料,下载 ...
- Linux内核之进程和文件共享
1.Shell命令的执行和进程 Shell 命令可以是内部或者外部命令. 内部(内置)命令(internal (built-in) command)的代码本身就是shell进程的一部分.L ...
- [转]Hibernate中property-ref的应用,常用来解决遗留数据库One To Many关系
[转]Hibernate中property-ref的使用,常用来解决遗留数据库One To Many关系 1.如表Class(ClassID,Class_No,ClassName)与Student(S ...
- 滴滴专车司机苹果手机ios客户端可以下载了
申请过滴滴专车司机的朋友都知道,滴滴专车就是滴滴打车的司机端,但是只有安卓的,一直没有苹果IOS的版本,很多申请通过审核的车主恼于没有IOS版本而暂无法使用滴滴专车司机客户端,也就意味着不能上线接单. ...
- Spring、Bean 的作用域
Singleton作用域(默认) 当一个bean的作用域为singleton,那么Spring Ioc容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则 ...
- 网易云课堂_C语言程序设计进阶_第二周:指针:取地址运算和指针、使用指针、指针与数组、指针与函数、指针与const、指针运算、动态内存分配_2信号报告
2 信号报告(5分) 题目内容: 无线电台的RS制信号报告是由三两个部分组成的: R(Readability) 信号可辨度即清晰度. S(Strength) 信号强度即大小. 其中R位于报告第一 ...
- Oracle方向
从毕业到现在工作已经4年了,入职前去过私企,干过外企,当前到了国企,各有各的不同,对于不同的人,有不同的适合的选择. 这几年的工作中也积累了不少知识,业务上的.技术上的,但始终觉得没有掌握一门核心,没 ...
- 2014.12.01 B/S 使用VS建立Web网站
要求:从hr数据库info表读取数据,在Web网站中显示为如图: 用DW绘制一个表格,然后将代码拷贝到新建的网站主页代码中 <div> <table bgcolor=" w ...