• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

HashMap重写equals和hashcode的问题

武飞扬头像
桂亭亭
帮助1

目录

什么时候对equals,hashcode重写?

什么是hashcode方法?

为什么在Hashmap中重写equals一定要对hashcode重写?

怎样重写hashcode与equals方法?

hashCode书写方法

为什么使用31?为什么使用hashCode方法


什么时候对equals,hashcode重写?

1 当需要比较对象是否相同时需要重写equals

2 当需要使用HashMap并且需要重写equals方法时,都需要重写hashcode方法!不需要使用hashmap的话是不需要重写的

什么是hashcode方法?

hashcode方法是Java的java.lang.Object提供的本地方法,这个方法在jvm中实现,它能返回当前对象在内存中地址。

public native int hashCode();

为什么在Hashmap中重写equals一定要对hashcode重写?

1(正向论证) HashMap在put一个键值对时,会先根据键的hashCodeequals方法来同时判断该键在容器(红黑树或表)中是否已经存在,如果存在则覆盖,反之新建。所以如果我们在重写equals方法时,没有重写hashCode方法,那么hashCode方法还是会默认使用Object提供的原始方法,而Object提供的hashCode方法返回值是不会重复的(也就是说每个对象返回的值都不一样)。所以就会导致每个对象在HashMap中都会是一个新的键。

2(反向论证) 若一个类中重写了 equals 方法,没有重写hashCode方法;且该类的两个对象具有不同属性但 hashCode 相等(有可能是相等的),在hashMap 以该对象为键进行存储时,会出现hash冲突现象,但发现该类重写了equals 方法,且通过该类的equals 比较之后也是相等,就会出现 hashMap 中只保存了一个对象,采用get 方法获取时,就会获取到别的对象,从而导致获取对象错乱。

怎样重写hashcode与equals方法?

我们直接上实例,然后再说明

  1.  
    import org.w3c.dom.Entity;
  2.  
     
  3.  
    import java.util.HashMap;
  4.  
    import java.util.Map;
  5.  
    import java.util.Objects;
  6.  
     
  7.  
    public class Main {
  8.  
    public static void main(String[] args) {
  9.  
    Map_1();
  10.  
    }
  11.  
    public static void Map_1()
  12.  
    {
  13.  
    Student s1=new Student("张三",21,"男","net2班");
  14.  
    Student s2=new Student("李四",22,"女","java1班");
  15.  
    boolean s=s1.equals(s2);
  16.  
    System.out.println(s1.toString());
  17.  
    System.out.println(s2.toString());
  18.  
     
  19.  
    HashMap<Student,Integer> ha1=new HashMap<Student, Integer>();
  20.  
    ha1.put(s1,32);
  21.  
    ha1.put(s2,122);
  22.  
    for(Map.Entry<Student,Integer> entry:ha1.entrySet()){
  23.  
    System.out.println(entry.getKey());
  24.  
    System.out.println(entry.getValue());
  25.  
    }
  26.  
    }
  27.  
    }
  28.  
     
  29.  
    class Student {
  30.  
    private String name;
  31.  
    private Integer age;
  32.  
    private String sex;
  33.  
    private String className;
  34.  
     
  35.  
    Student(String name, Integer age, String sex, String className) {
  36.  
    this.name = name;
  37.  
    this.age = age;
  38.  
    this.sex = sex;
  39.  
    this.className = className;
  40.  
    }
  41.  
     
  42.  
    public String getName() {
  43.  
    return name;
  44.  
    }
  45.  
     
  46.  
    public void setName(String name) {
  47.  
    this.name = name;
  48.  
    }
  49.  
     
  50.  
    public Integer getAge() {
  51.  
    return age;
  52.  
    }
  53.  
     
  54.  
    public void setAge(int age) {
  55.  
    this.age = age;
  56.  
    }
  57.  
     
  58.  
    public String getSex() {
  59.  
    return sex;
  60.  
    }
  61.  
     
  62.  
    /**
  63.  
    * @param sex 男 女
  64.  
    */
  65.  
    public boolean setSex(String sex) {
  66.  
    if (!Objects.equals(sex, "男") && !Objects.equals(sex, "女")) {
  67.  
    return false;
  68.  
    } else {
  69.  
    this.sex = sex;
  70.  
    return true;
  71.  
    }
  72.  
     
  73.  
    }
  74.  
     
  75.  
    public String getClassName() {
  76.  
    return className;
  77.  
    }
  78.  
     
  79.  
    public void setClassName(String className) {
  80.  
    this.className = className;
  81.  
    }
  82.  
     
  83.  
    @Override
  84.  
    public String toString() {
  85.  
    return name " " sex " " age " " className;
  86.  
    }
  87.  
     
  88.  
    @Override
  89.  
    public boolean equals(Object o) {
  90.  
    if (o instanceof Student) {
  91.  
    return Objects.equals(((Student) o).getName(), this.name) && Objects.equals(((Student) o).getAge(), this.age) && Objects.equals(((Student) o).getClassName(), this.className) && Objects.equals(((Student) o).getSex(), this.sex);
  92.  
    } else
  93.  
    return false;
  94.  
    }
  95.  
     
  96.  
    @Override
  97.  
    public int hashCode() {
  98.  
    final int prime = 31;
  99.  
    int result = 1;
  100.  
    result = prime * result ((sex == null) ? 0 : sex.hashCode());
  101.  
    result = prime * result ((name == null) ? 0 : name.hashCode());
  102.  
    result = prime * result ((className == null) ? 0 : className.hashCode());
  103.  
    result = prime * result (age == null ? 0 : age.hashCode());
  104.  
     
  105.  
    return result;
  106.  
    }
  107.  
    }
学新通
学新通
运行截图

hashCode书写方法

1 我们比较对象中的每一个属性 如果属性==null,我们返回hashcode为0,

反之将调用hashCode方法获得当前属性的地址 (31*result) 并将结果赋值给result

2 直到每一个属性都已比较完成,我们返回累加的result值

为什么使用31?为什么使用hashCode方法

1    其实每次计算result*31的作用是为了,防止hash冲突!因为如果不设置一个乘积因子,result计算的结果比较小,非常容易在累加的过程后出现相同的hash值,这种情况不是我们想见到的!

   

2   首先我们需要知道,我们是通过对象的域来计算hash的, 在对象中域无非数组、引用类型、基本数据类型,有这么多类型的域,我们肯定不能选择某一个域的hash值来作为对象的hashcode方法的返回值;因此我们考虑将域的hash值累加起来返回!

  • 基本数据类型,大家可以参考其对应的包装类型的hashcode方法
  • (我们可以发现实例代码中age属性使用的是Integer而不是int类型)
  • 引用类型则直接调用hashcode()
  • 数组类型则需要遍历数组,依次调用hashcode()

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgakeca
系列文章
更多 icon
同类精品
更多 icon
继续加载