如果你重载了equals,比如说是基于对象的内容实现的,而保留hashCode的实现不变,那么很可能某两个对象明明是“相等”,而hashCode却不一样。
这样,当你用其中的一个作为键保存到hashMap、hasoTable或hashSet中,再以“相等的”找另一个作为键值去查找他们的时候,则根本找不到。
引用别人说的一段话哈~
一般来说,如果你要把一个类的对象放入容器中,那么通常要为其重写equals()方法,让他们比较地址值而不是内容值。特别地,如果要把你的类的对象放入散列中,那么还要重写hashCode()方法;要放到有序容器中,还要重写compareTo()方法。
equals()相等的两个对象,hashcode()一定相等;
equals()不相等的两个对象,却并不能证明他们的hashcode()不相等。换句话说,equals()方法不相等的两个对象,hashcode()有可能相等。(我的理解是由于哈希码在生成的时候产生冲突造成的)。
反过来:hashcode()不等,一定能推出equals()也不等;hashcode()相等,equals()可能相等,也可能不等
我的理解哈,
不同的key有可能是一样的code,所以需要再用equals来处理hash冲突,其实只要拿个equals也行,但是效率会降低
在list对象中也存在同样的问题,也需要重写equals方法
这些都是我的老师告诉我的,其实我在用arraylist的时候存储的比较简单,但是老师让我加一些附加信息,不重写的话,比较的是内存地址,那么如果你不断的new,它会认为是相同的
重写hashCode()时最重要的原因就是:无论何时,对同一个对象调用hashCode()都应该生成同样的值。如果在将一个对象用put()方法添加进HashMap时产生一个hashCode()值,而用get()取出时却产生了另外一个 hashCode()值,那么就无法重新取得该对象了。所以,如果你的hashCode()方法依赖于对象中易变的数据,那用户就要小心了,因为此数据发生变化时,hashCode()就会产生一个不同的hash码,相当于产生了一个不同的“键”。
Object的hashCode()方法,返回的是当前对象的内存地址。下次如果我们需要取一个一样的“键”对应的键值对的时候,我们就无法得到一样的hashCode值了。因为我们后来创建的“键”对象已经不是存入HashMap中的那个内存地址的对象了。
我们看一个简单的例子,就能更加清楚的理解上面的意思。假定我们写了一个类:Person (人),我们判断一个对象“人”是否指向同一个人,只要知道这个人的身份证号一直就可以了。
先来个没有重写Code类的hashcode()的例子吧,看看是什么效果:
- package com.fit;
- import java.util.HashMap;
- /**
- * 身份证类
- *
- * @author ZYD
- *
- */
- public class Code {
- /**
- * 身份证号码,一旦确定就不能更改
- */
- private final int id;
- public int getId() {
- return id;
- }
- /**
- * 通过构造方法确定身份证号码
- *
- * @param id
- */
- public Code(int id) {
- this.id = id;
- }
- /**
- * 重写equals()方法
- */
- public boolean equals(Object o) {
- // 如果地址一样,则两个对象相同
- if (this == o) {
- return true;
- }
- // 如果两个对象是同一类型,则比较其属性值是否都相同。如果都相同,则说明两个对象也相同;否则,说明这两个对象不相同。
- if (o instanceof Code) {
- Code co = (Code) o;
- boolean b = (co.id == this.id);
- return b;
- }
- return false;
- }
- /**
- * 重写toString()方法
- */
- public String toString() {
- return "【身份证】:" + id;
- }
- /**
- * 测试
- * @param args
- */
- public static void main(String[] args) {
- HashMap<Code, Person> map = new HashMap<Code, Person>();
- Person p1 = new Person(new Code(10001),"张三");
- Person p2 = new Person(new Code(10002),"李四");
- map.put(p1.getCode(), p1);
- map.put(p2.getCode(), p2);
- System.out.println("HashMap 中存放的人员信息:\n"+map);
- //张三改名为张山,身份证号不变。
- Person p3 = new Person(new Code(10001),"张山");
- map.put(p3.getCode(), p3);
- System.out.println("张三改名为张山后 HashMap 中存放的人员信息:\n"+map);
- //查找身份证为10001 的人员信息
- System.out.println("查找身份证为:10001 的人员信息:"+map.get(new Code(10001)));
- }
- }
- /**
- * 人类
- * @author Administrator
- *
- */
- class Person {
- /**
- * 每一个成人都有一个身份证
- */
- private Code code;
- /**
- * 姓名
- */
- private String name;
- public Code getCode() {
- return code;
- }
- public void setCode(Code code) {
- this.code = code;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public Person() {
- }
- public Person(Code code, String name) {
- this.code = code;
- this.name = name;
- }
- /**
- * 重写equals()方法 当两个人得身份证号相同以及姓名相同时,表示这两个人是同一个人。
- */
- public boolean equals(Object o) {
- if (o == this) {
- return true;
- }
- if (o instanceof Person) {
- Person p = (Person) o;
- boolean b = this.code.equals(p.code) && this.name.equals(p.name);
- return b;
- }
- return false;
- }
- /**
- * 重写toString()方法
- */
- public String toString() {
- return "【姓名】:" + name + " ";
- }
- }
运行结果:
HashMap 中存放的人员信息:
{【身份证】:10002=【姓名】:李四 , 【身份证】:10001=【姓名】:张三 }
张三改名为张山后 HashMap 中存放的人员信息:
{【身份证】:10002=【姓名】:李四 , 【身份证】:10001=【姓名】:张三 , 【身份证】:10001=【姓名】:张山 }
查找身份证为:10001 的人员信息:null
从上面的结果可以看出:
我们所做的更新和查找操作都失败了。失败的原因就是我们的身份证类:Code 没有覆写hashCode()方法。这个时候,当查找一样的身份证号码的键值对的时候,使用的是默认的对象的内存地址来进行定位。这样,后面的所有的身份证号对象
new Code(10001) 产生的hashCode()值都是不一样的,所以导致操作失败。
重写Code类的hashcode(),代码上:
- package com.fit;
- import java.util.HashMap;
- /**
- * 身份证类
- *
- * @author ZYD
- *
- */
- public class Code {
- /**
- * 身份证号码,一旦确定就不能更改
- */
- private final int id;
- public int getId() {
- return id;
- }
- /**
- * 通过构造方法确定身份证号码
- *
- * @param id
- */
- public Code(int id) {
- this.id = id;
- }
- /**
- * 重写equals()方法
- */
- public boolean equals(Object o) {
- // 如果地址一样,则两个对象相同
- if (this == o) {
- return true;
- }
- // 如果两个对象是同一类型,则比较其属性值是否都相同。如果都相同,则说明两个对象也相同;否则,说明这两个对象不相同。
- if (o instanceof Code) {
- Code co = (Code) o;
- boolean b = (co.id == this.id);
- return b;
- }
- return false;
- }
- /**
- * 重写hashcode()方法,以身份证号码作为hash码。
- *
- * @return
- */
- public int hashCode() {
- return id;
- }
- /**
- * 重写toString()方法
- */
- public String toString() {
- return "【身份证】:" + id;
- }
- /**
- * 测试
- * @param args
- */
- public static void main(String[] args) {
- HashMap<Code, Person> map = new HashMap<Code, Person>();
- Person p1 = new Person(new Code(10001),"张三");
- Person p2 = new Person(new Code(10002),"李四");
- map.put(p1.getCode(), p1);
- map.put(p2.getCode(), p2);
- System.out.println("HashMap 中存放的人员信息:\n"+map);
- //张三改名为张山,身份证号不变。
- Person p3 = new Person(new Code(10001),"张山");
- map.put(p3.getCode(), p3);
- System.out.println("张三改名为张山后 HashMap 中存放的人员信息:\n"+map);
- //查找身份证为10001 的人员信息
- System.out.println("查找身份证为:10001 的人员信息:"+map.get(new Code(10001)));
- }
- }
- /**
- * 人类
- * @author Administrator
- *
- */
- class Person {
- /**
- * 每一个成人都有一个身份证
- */
- private Code code;
- /**
- * 姓名
- */
- private String name;
- public Code getCode() {
- return code;
- }
- public void setCode(Code code) {
- this.code = code;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public Person() {
- }
- public Person(Code code, String name) {
- this.code = code;
- this.name = name;
- }
- /**
- * 重写equals()方法 当两个人得身份证号相同以及姓名相同时,表示这两个人是同一个人。
- */
- public boolean equals(Object o) {
- if (o == this) {
- return true;
- }
- if (o instanceof Person) {
- Person p = (Person) o;
- boolean b = this.code.equals(p.code) && this.name.equals(p.name);
- return b;
- }
- return false;
- }
- /**
- * 重写toString()方法
- */
- public String toString() {
- return "【姓名】:" + name + " ";
- }
- }
运行效果:
HashMap 中存放的人员信息:
{【身份证】:10001=【姓名】:张三 , 【身份证】:10002=【姓名】:李四 }
张三改名为张山后 HashMap 中存放的人员信息:
{【身份证】:10001=【姓名】:张山 , 【身份证】:10002=【姓名】:李四 }
查找身份证为:10001 的人员信息:【姓名】:张山