JAVA中重写equals方法为啥要重写hashcode方法说明

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA中重写equals方法为啥要重写hashcode方法说明相关的知识,希望对你有一定的参考价值。

重写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 的人员信息:【姓名】:张山 

参考技术A

我认为首先要认清equals方法和hashcode方法是用来干嘛的,然后这两个之间什么关系就够了为什么重写equals()就一定要重写hashCode()方

JAVA中重写equals()方法的同时要重写hashcode()方法

object对象中的 public boolean equals(Object obj),对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象时,此方法才返回 true;
注意:当此方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。如下:
(1)当obj1.equals(obj2)为true时,obj1.hashCode() == obj2.hashCode()必须为true 
(2)当obj1.hashCode() == obj2.hashCode()为false时,obj1.equals(obj2)必须为false
如果不重写equals,那么比较的将是对象的引用是否指向同一块内存地址,重写之后目的是为了比较两个对象的value值是否相等。特别指出利用equals比较八大包装对象
(如int,float等)和String类(因为该类已重写了equals和hashcode方法)对象时,默认比较的是值,在比较其它自定义对象时都是比较的引用地址
hashcode是用于散列数据的快速存取,如利用HashSet/HashMap/Hashtable类来存储数据时,都是根据存储对象的hashcode值来进行判断是否相同的。
这样如果我们对一个对象重写了euqals,意思是只要对象的成员变量值都相等那么euqals就等于true,但不重写hashcode,那么我们再new一个新的对象,
当原对象.equals(新对象)等于true时,两者的hashcode却是不一样的,由此将产生了理解的不一致,如在存储散列集合时(如Set类),将会存储了两个值一样的对象,
导致混淆,因此,就也需要重写hashcode()
总结,自定义类要重写equals方法来进行等值比较,自定义类要重写compareTo方法来进行不同对象大小的比较,重写hashcode方法为了将数据存入HashSet/HashMap/Hashtable类时进行比较









以上是关于JAVA中重写equals方法为啥要重写hashcode方法说明的主要内容,如果未能解决你的问题,请参考以下文章

JAVA 为啥要重写equals 方法才能对一个值进行操作(容器)

java中重写Object类的equals方法为啥要重写hashcode方法?不重写可以吗?

java中重写Object类的equals方法为啥要重写hashcode方法?不重写可以吗?

【彻底理解】 为啥重写equals()方法为啥要重写hashCode()方法

为啥要重写toString方法和hashcode方法

java 基础笔记--hashCode(),你好,为啥要重写