资讯专栏INFORMATION COLUMN

面试官让你说说==和equals()的区别,重写equals必须重写hashcode方法吗

1fe1se / 1637人阅读

摘要:如果我们不重写的方法,那么就会默认调用的方法小王小王我们可以看到以上的运行结果违背了的规定如果返回,那么方法必须返回相同的整数所以我们需要对对象的方法进行重写通过重写让其与对象的属性关联起来,那么就能够达到为,那么的值也相等。

面试官让你说说==和equals()的区别,重写equals必须重写hashcode方法吗

本身特质来说

==:操作符

equals():方法

适用对象

==:主要用于基本类型之间的比较(char、Boolean、byte、short、int、long、float、dobule),也可以用于比较对象

equals():对象之间的比较(基本类型的包装器类型,string,自己定义的对象等)

比较对象时的区别

==:比较两个对象是否指向同一个对象,也就是说他们指向的对象的首地址是否相同

equals():可以通过重写equals方法从而比较对象的内容是否相同,如果不重写那么和==符号没有区别,都是比较的对象的引用是否指向同一个对象

对于一个对象student来说,如果我们不重写它的equals方法,那么和==符号一样比较的是对象的引用而不是内容

public class Student {
    private int id;
    private String name;
    private String password;


    public Student(int id, String name, String password) {
        this.id = id;
        this.name = name;
        this.password = password;
    }

}
public class Test2 {
    public static void main(String[] args){

        Student s1 = new Student(1, "小王", "123456");
        Student s2 = new Student(1, "小王", "123456");
        System.out.println(s1 == s2);//false

        System.out.println(s1.equals(s2));//false
    }
}

上面两个对象s1和s2不相等,因为他们指向的是两个不同的对象,所以引用不同,但是我们的目的是要达到如果id,name,password都相同,那么就是同一个对象,所以需要重写equals()方法

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    Student student = (Student) o;

    if (id != student.id) return false;
    if (name != null ? !name.equals(student.name) : student.name != null) return false;
    return password != null ? password.equals(student.password) : student.password == null;
}

这个时候我们再运行

public class Test2 {
    public static void main(String[] args){

        Student s1 = new Student(1, "小王", "123456");
        Student s2 = new Student(1, "小王", "123456");
        System.out.println(s1 == s2);//false
        System.out.println(s1.equals(s2));//true
    }
}

对于string类型来说,它的的equals()方法是对object方法的equals()进行了重写,从而比较的字符串序列是

否相同如下:

String s1 = new String("abc");//s1存在于堆内存中
String s2 = new String("abc");//s2也存在于堆内存中
System.out.println(s1 == s2);//false s1和s2指向的对象的首地址不一样,不是同一个对象
System.out.println(s1.equals(s2));//true  s1和s2指向的对象的内容相同

ps:

String s3 = "abc";
String s4 = "abc";
System.out.println(s3 == s4);//true 
System.out.println(s3.equals(s4));//true

接下来我们讨论一下重写equals()方法的同时必须要重写hashcode()方法吗

​ 首先我们重写equals()的目的就是为了让内容相同的对象让它们相同,而不是单单只比较对象的引用(对象的首地址),也就是尽管这两个对象的引用地址不同,但是我们调用equals方法的时候仍然返回true

​ 那么这个时候我们为什么又要重写hashcode方法呢,hashcode()返回的是对象的地址,是一个散列值,那么如果我们通过equals()方法得到这两个对象相同,尽管他们在堆中的内存地址不一样,但是我们希望他们的哈希值是一样的,这样如果存入map的话,就能定位到相同的索引

​ 同时Java标准中对hashcode有如下的规定:

在java应用程序执行期间,如果在equals方法比较中所用的信息没有被修改,那么在同一个对象上多次调用hashCode方法时必须一致地返回相同的整数。如果多次执行同一个应用时,不要求该整数必须相同。

如果两个对象通过调用equals方法是相等的,那么这两个对象调用hashCode方法必须返回相同的整数。

如果两个对象通过调用equals方法是不相等的,不要求这两个对象调用hashCode方法必须返回不同的整数。

如果我们不重写student的hashcode()方法,那么就会默认调用object的hashcode()方法:

public class Test2 {
    public static void main(String[] args){

        Student s1 = new Student(1, "小王", "123456");
        Student s2 = new Student(1, "小王", "123456");
        System.out.println(s1 == s2);//false
        System.out.println(s1.equals(s2));//true
        System.out.println(s1.hashCode());//356573597
        System.out.println(s2.hashCode());//1735600054
    }
}

我们可以看到以上的运行结果违背了hashcode的规定:如果equals()返回true,那么hashcode方法必须返回相同的整数

所以我们需要对student对象的hashcode方法进行重写

@Override
public int hashCode() {
    int result = id;
    result = 31 * result + (name != null ? name.hashCode() : 0);
    result = 31 * result + (password != null ? password.hashCode() : 0);
    return result;
}

通过重写hashcode()让其与对象的属性关联起来,那么就能够达到equals()为true,那么hashcode的值也相等。

现在我们已经知道了重写equals()方法的同时需要重写对象的hashcode()方法,让其满足hashcode的标准条件。

但是好奇的同学可能会想到:为什么hashcode需要这样定义标准呢,这样做到底有什么好处呢,除了让equals()方法和hashcode()方法的返回值具有一致性。

这时我们就需要提到map类了,我们知道hashmap的结构是一个数组加链表组成的,我们通过key的

​ hashcode % hashmap的capacity 定位到具体数组的索引,然后将该(key,value)放入该索引对应的链表里面,这里之所以为链表就是为了解决hash冲突,即hashcode % capacity 相同的值有很多,需要用一个链表存储起来,如果想要链表短一点,也就是hash冲突少一点,那么就需要减小hashmap的负载因子loadFacotor,当然这里也就扯远了,我们继续回到正题,

Student s1 = new Student(1, "小王", "123456");
Student s2 = new Student(1, "小王", "123456");

​ 对于s1和s2两个对象,如果我们我们已经将s1存入一个map对象,那么我们再存入s2时,我们希望的是这是不能再插入map了,因为此时map中已经存在小王这个对象了,那么如何才能做到呢

​ 首先我们通过s1的hashcode % capacity 得到了一个数组索引,然后将s1这个对象存入map,那么我们再插入s2的时候同样也需要计算它的hashcode,然后定位到相同的数组索引,然后判断该链表中是否存在小王这样一个对象,如果存在就不put

​ 所以我们需要得到的s1和s2的hashcode相同,才能避免同一个对象被put进入map中多次,所以我们才需要在重写equals()方法的同时重写equals()方法,让两个相等的对象具有相同的hashcode

​ 可能细心的盆友会发现如果我们只是需要简单的根据判断两个对象的内容是否相同来判断两个对象是否相等,而不涉及到ma"p操作,那么其实也是不用重写ha"shcode方法了,但是万一哪天突然不小心放进了map了呢,所以一般我们重写equals()方法的同时都会重写hashcode(),确保万无一失~

参考

重写equal()时为什么也得重写hashCode()之深度解读equal方法与hashCode方法渊源

重写equals方法后重写hashCode方法的必要性

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/77773.html

相关文章

  • 面试官:“你重写hashcode equals 么,为什么重写equals必须重写hash

    摘要:介绍的作用是获取哈希码,也称为散列码它实际上是返回一个整数。所以具有相索引的对象,在该散列码位置处存在多个对象,我们必须依靠的和本身来进行区分。 1.hashCode介绍 hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个散列码的作用是确定该对象在散列表中的索引位置,如果有看我的上一篇文章 什么是散列表,那么这里的散列码就相当于上文中根据首字母查...

    asce1885 评论0 收藏0
  • 【金三银四】面试题之java基础

    摘要:中,任何未处理的受检查异常强制在子句中声明。运行时多态是面向对象最精髓的东西,要实现运行时多态需要方法重写子类继承父类并重写父类中已 1、简述Java程序编译和运行的过程:答:① Java编译程序将Java源程序翻译为JVM可执行代码--字节码,创建完源文件之后,程序会先被编译成 .class 文件。② 在编译好的java程序得到.class文件后,使用命令java 运行这个 .c...

    Yangyang 评论0 收藏0
  • 【金三银四】面试题之java基础

    摘要:中,任何未处理的受检查异常强制在子句中声明。运行时多态是面向对象最精髓的东西,要实现运行时多态需要方法重写子类继承父类并重写父类中已 1、简述Java程序编译和运行的过程:答:① Java编译程序将Java源程序翻译为JVM可执行代码--字节码,创建完源文件之后,程序会先被编译成 .class 文件。② 在编译好的java程序得到.class文件后,使用命令java 运行这个 .c...

    Barrior 评论0 收藏0
  • Java知识体系之Java基础

    摘要:最近看到上面的一篇博客面试必备最常见的面试题全解析讲解了关于体系的一些模块以及面试中的一些常见问题虽然最近没有要去找工作的需求但是巩固一下这方面的知识还是很有必要的后面从作者提出的问题进行自我的提问与解答有问题欢迎大家指出基础部分和的区别我 最近看到CSDN上面的一篇博客 面试必备:《Java最常见的200+面试题全解析》, 讲解了关于Java体系的一些模块以及面试中的一些常见问题; ...

    zhou_you 评论0 收藏0
  • Java Object对象hashcodeequals方法

    摘要:在中对象是一切对象都会自动继承的一个类,在这个类中定义的属性和方法可以说是每个类都必须的。这里有必要说说这里对象里面的几个方法返回该对象的哈希码值。这些基于表的集合,只能要求被存放的对象实现自己的方法,保证的均匀性。 Object 在Java中Object对象是一切对象都会自动继承的一个类,在这个类中定义的属性和方法可以说是每个类都必须的。 这里有必要说说这里对象里面的几个方法 has...

    chnmagnus 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<