查看原文
其他

【127期】面试官:JavaBean 为什么要重写 hashCode() 方法和 equals 方法?

Java精选 2022-08-09

点击上方“Java精选”,选择“设为星标”

别问别人为什么,多问自己凭什么!

下方留言必回,有问必答!

每天 08:00 更新文章,每天进步一点点...

记得有一次去面试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的性能降低,因为不能快速定位了。更多面试题公众号Java精选,回复Java面试,获取面试题资料。

还有一种情况就是两个对象的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,公众号:Java精选,又你想要的*/
  
 }
}
三、如何重写这两个方法?(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;  
    }  
 
}

作者:Joeliawu

blog.csdn.net/qq_36090463/article/details/81102713

精品资料,超赞福利!

 - 小程序,3000+ 道面试题在线刷,最新、最全 Java 面试题!

期往精选  点击标题可跳转

【119期】面试官问:了解过 JDK8 中常量池吗?说说运行时的常量池!

【120期】阿里大佬开源 easyexcel,史上最全实现 Excel 导入导出!

【121期】面试官问:线程池执行过程中遇到异常会发生什么,如何处理?

【122期】如何画出一张优秀的架构图(老鸟必备)

【123期】字节三面:toString()、String.valueOf、String 强转,有啥区别?

【124期】字节一面面试官问:Java 如何实现链表中归并排序?

【125期】面试官:private 方法能够通过反射访问,那么 private 还有什么意义?

【126期】京东一面:说说 ThreadLocal 的使用场景及使用方式?

文章有帮助的话,在看,转发吧!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存