为什么要重写equals和hash


prtyaa
prtyaa 2023-12-30 23:02:37 63301
分类专栏: 资讯

记得有一次去面试Java软件开发工程师,面试官问了我一个关于JavaBean为什么要重写hashCode()方法和equals方法,我记得当时我巴拉巴拉半天就是没有说到重点,现在想一想归根到底还是我对这两个的理解不深刻,现在我特定来总结下:hashCode 方法用于散列集合的查找,equals 方法用于判断两个对象是否相等。

一、我们为什么需要重写hashCode()方法和equals()方法?(Why)

有时在我们的业务系统中判断对象时有时候需要的不是一种严格意义上的相等,而是一种业务上的对象相等。在这种情况下,原生的equals方法就不能满足我们的需求了.

我们所知道的JavaBean的超类(父类)是Object类,JavaBean中的equals方法是继承自Object中的方法.Object类中定义的equals()方法是用来比较两个引用所指向的对象的内存地址是否一致.并不是比较两个对象的属性值是否一致,所以这时我们需要重写equals()方法.

Object类中equals()方法的源码

public boolean equals(Object obj) {
 
       return (this == obj);
 
}

public class Demo {
 public static void main(String[] args) {
  Student stu1 = new Student("awu",22);
  Student stu2 = new Student("awu",22);
  System.out.println(stu1.equals(stu2));
                /*因为Student这个JavaBean没有重写关于属性值相等的equals()方法
                  ,所以默认比较的是地址值,从而输出结果为false*/    
 }
}

那么为什么在重写equals方法的时候需要重写hashCode方法呢?

主要是Object.hashCode的通用约定:

  • 在java应用程序运行时,无论何时多次调用同一个对象时的hsahCode()方法,这个对象的hashCode()方法的返回值必须是相同的一个int值.
  • 如果两个对象equals()返回值为true,则他们的hashCode()也必须返回相同的int值.
  • 如果两个对象equals()返回值为false,则他们的hashCode()返回值也必须不同.

以HashSet来说明为什么要这么约定:HashSet存放元素时,根据元素的hashCode值快速找到要存储的位置,如果这个位置有元素,两个对象通过equals()比较,如果返回值为true,则不放入;如果返回值为false,则这个时候会以链表的形式在同一个位置上存放两个元素,这会使得HashSet的性能降低,因为不能快速定位了。

还有一种情况就是两个对象的hashCode()返回值不同,但是equals()返回true,这个时候HashSet会把这两个对象都存进去,这就和Set集合不重复的规则相悖了;所以,我们重写了equals()方法时,要按照b,c规则重写hashCode()方法!(其实就是如果只重写了 equals 方法,两个对象 equals 返回了true,但是如果没有重写 hashCode 方法,集合还是会插入元素。这样集合中就出现了重复元素了。)

推荐:

二、在什么情况下需要重写hashCode()方法和equals()方法? (When)

当我们自定义的一个类,想要把它的实例保存在以Hash散列查找的集合中时,我们就需要重写这两个方法;

public class Student {
 private String name;
 
 private Integer age;
 
 public Student(){
  
 }
 
 public Student(String name,Integer age){
  this.name = name;
  this.age = age;
 }
 
 public String getName() {
  return name;
 }
 
 public void setName(String name) {
  this.name = name;
 }
 
 public Integer getAge() {
  return age;
 }
 
 public void setAge(Integer age) {
  this.age = age;
 }
 
 @Override  
    public int hashCode(){  
        final int prime = 31;  
        int result = 17;  
        result = prime * result + name.hashCode();  
        result = prime * result + age;  
        return result;  
    }  
 
    @Override  
    public boolean equals(Object obj){  
        if(this == obj)  
            return true;  
        if(obj == null)  
            return false;  
        if(getClass() != obj.getClass())  
            return false;  
        final Student other = (Student)obj;  
        if(name.equals(other.name)){  
            return false;  
        }  
        if(age.equals(other.age)){  
            return false;  
        }  
        return true;  
    }  
 
}

public class Demo {
 public static void main(String[] args) {
  Student stu1 = new Student("awu",22);
  Student stu3 = new Student("awu",33);
  Student stu2 = new Student("awu",22);
  
  Set set = new HashSet();
  set.add(stu1);
  set.add(stu2);
  set.add(stu3);
  
  System.out.println(set.size());
                /*输出结果为2*/
  
 }
}

如果不是以Hash散列查找的集合,即使重写HashCode也没多大实际用处.比如如下栗子:

public class Demo {
 public static void main(String[] args) {
  Student stu1 = new Student("awu",22);
  Student stu3 = new Student("awu",33);
  Student stu2 = new Student("awu",22);
  
  ArrayList list = new ArrayList();
  list.add(stu1);
  list.add(stu2);
  list.add(stu3);
  
  System.out.println(list .size());
                /*输出结果为3*/
  
 }
}

三、如何重写这两个方法?(How)

public class Student {
 private String name;
 
 private Integer age;
 
 public Student(){
  
 }
 
 public Student(String name,Integer age){
  this.name = name;
  this.age = age;
 }
 
 public String getName() {
  return name;
 }
 
 public void setName(String name) {
  this.name = name;
 }
 
 public Integer getAge() {
  return age;
 }
 
 public void setAge(Integer age) {
  this.age = age;
 }
 
     @Override  
        public int hashCode(){  
            final int prime = 31;  
            int result = 17;  
            result = prime * result + name.hashCode();  
            result = prime * result + age;  
            return result;  
        }  
 
        @Override  
        public boolean equals(Object obj){  
            if(this == obj)  
                return true;  
            if(obj == null)  
                return false;  
            if(getClass() != obj.getClass())  
                return false;  
                final Student other = (Student)obj;  
            if(name.equals(other.name)){  
                return false;  
            }  
            if(age.equals(other.age)){  
                return false;  
            }  
            return true;  
    }  
 
}

网站声明:如果转载,请联系本站管理员。否则一切后果自行承担。

本文链接:https://www.xckfsq.com/news/show.html?id=32960
赞同 0
评论 0 条
prtyaaL1
粉丝 1 发表 2554 + 关注 私信
上周热门
银河麒麟添加网络打印机时,出现“client-error-not-possible”错误提示  1489
银河麒麟打印带有图像的文档时出错  1407
银河麒麟添加打印机时,出现“server-error-internal-error”  1196
统信操作系统各版本介绍  1118
统信桌面专业版【如何查询系统安装时间】  1116
统信桌面专业版【全盘安装UOS系统】介绍  1071
麒麟系统也能完整体验微信啦!  1029
统信【启动盘制作工具】使用介绍  674
统信桌面专业版【一个U盘做多个系统启动盘】的方法  618
信刻全自动档案蓝光光盘检测一体机  529
本周热议
我的信创开放社区兼职赚钱历程 40
今天你签到了吗? 27
信创开放社区邀请他人注册的具体步骤如下 15
如何玩转信创开放社区—从小白进阶到专家 15
方德桌面操作系统 14
我有15积分有什么用? 13
用抖音玩法闯信创开放社区——用平台宣传企业产品服务 13
如何让你先人一步获得悬赏问题信息?(创作者必看) 12
2024中国信创产业发展大会暨中国信息科技创新与应用博览会 9
中央国家机关政府采购中心:应当将CPU、操作系统符合安全可靠测评要求纳入采购需求 8

添加我为好友,拉您入交流群!

请使用微信扫一扫!