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了 ...
随机推荐
- juce中的Singleton
说明上其实很明白,支持多线程,防止重复创建,同时支持如果删除以后就不在创建,利用局部静态变量进行标记.挺通用,看来下次写个c11版本的 //============================== ...
- Bootstrap之Button.js
查看Button.js的源代码 +function ($) { 'use strict'; // BUTTON PUBLIC CLASS DEFINITION // ================= ...
- Python成长之路第一篇(2)-初识列表和元组
可以将列表和元组当成普通的“数组”,他能保存任意数量任意类型的Python对象,和数组一样都是通过数字0索引访问元素,列表和元组可以存储不同类型的对象,列表和元组有几处重要区别.列表元素用([])包括 ...
- jquery ajax提交及请求
jQuery.ajax({ url: dataURL, success: function(results) { var parsedJson = jQuery.parseJSON(results); ...
- JavaScript学习之—prototype
一.利用prototype扩展String方法,去除字符前后空格: String.prototype.trim = function String$trim() { if (arguments.len ...
- [Django 1.5] Windows + Apache + wsgi配置
基本步骤 下载安装Apache http://httpd.apache.org/download.cgi. 下载安装modwsgi 模块http://code.google.com/p/modwsgi ...
- Android第三方应用分享图文到微信朋友圈 & 微信回调通知分享状态
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAWQAAAKUCAIAAAC8A9XzAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWX ...
- 【POJ】2318 TOYS ——计算几何+二分
TOYS Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 10281 Accepted: 4924 Description ...
- 全国计算机等级考试二级教程-C语言程序设计_第11章_对函数的进一步讨论
无论传递什么参数,函数都有副本机制 改变一个变量,需要传入变量的地址 改变一个指针变量,需要传入指针变量的地址 //int add(int a, int b);挖取函数声明 //int ()(int ...
- iOS使用sqlite3原生语法进行增删改查以及FMDB的使用
首先要导入libsqlite3.dylib并且加入头文件#import <sqlite3.h>,在进行增删改查之前还要先把数据库搞进去. 一种方法是从外面拷贝到程序里:http://www ...