Java ==,equals()与hashcode()的使用

 更新时间:2023年05月22日 10:26:50   作者:按时交作业  
本文主要介绍了Java ==,equals()与hashcode()的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

==,equals()与hashcode()

"=="

在讲解之前,我们是怎么接触到==的,我们在作比较时经常用到 ==, 这个符号常用作基本类的数据。

==运算符通常用于比较基本数据类型(如int、long、double等)和枚举类型的值是否相等,而对于对象类型,==运算符用于比较它们的引用是否相等,即它们是否指向同一个对象。

思考一个问题,为什么我们一般不使用==来比较对象,如果两个对象的引用相同,即它们指向同一个对象,那么使用==运算符比较它们的引用会返回true,因为它们确实指向同一个对象。在这种情况下,两个对象的内容自然是相同的,因为它们是同一个对象。

那为啥我们不直接使用==去比较对象, 而要麻烦的使用其它的办法,

因为: 我们比较对象不是想看它的引用是否相同,而是里面的属性是否相同

在这种情况下,使用==运算符比较两个对象的引用并不能判断它们的内容是否相同,因为两个不同的对象可能具有相同的属性值,但它们的引用不同。因此,在比较对象是否相同时,应该根据对象的语义来实现equals()方法,而不是使用==运算符。

public class Main {
    public static void main(String[] args) {
        int a = 5;
        int b = 5;
        int c = 6;
        System.out.println(a==b); // true
        System.out.println(a==c); // false
        Person p1 = new Person("hhh", 15);
        Person p2 = new Person("hhh", 15);
        // 属性相同,但引用不同。按照常理应该被认作是相同的。实际却是不同的
        System.out.println(p1 == p2); // false
    }
}
class Person{
    String name;
    Integer age;
    Person(String name, Integer age){
        this.age = age;
        this.name = name;
    }
}

equals()方法

equals()方法是Object类中的方法,它仅仅是地址的比较,因此只能比较两个类是否是同一个类,而不能比较属性是否相同,因此,我们比较对象一般都会重写equals()方法

public class Point {
    private int x;
    private int y;
    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
    // getters and setters
    @Override
    public boolean equals(Object obj) {
        return (this == obj);
    }
}

如果一个类的属性包含基本数据类型和引用数据类型,那么这些属性值相同,但它们的引用地址也不一定相同。此时,必须重写equals()方法,根据对象的语义来进行比较,才能得到正确的结果。

列表中的使用

在Java中,列表类(如List)通常用来存储一组对象,当我们需要在列表中查找某个对象时,通常需要调用列表的contains()方法或indexOf()方法。这些方法会使用对象的equals()方法来比较对象是否相等。

它是通过比较对象的属性值从而去列表中查找。

public class Main {
    public static void main(String[] args) {
        List<String> list = List.of("A", "B", "C");
        // 下面的例子中即使对象的地址不同,但是属性值相同,因此在列表中能查到
        System.out.println(list.contains(new String("C"))); // true
        System.out.println(list.indexOf(new String("C"))); // 2
    }
}

在hash结构的表中使用

map是一种键值对的映射表,map使用一个很大的数组来存储value,然后通过keyhash值来查找value的索引

map其实可以看作一个数组,keyhashcode()值可以作为数组的索引,然后根据索引去查找value

那究竟在什么地方使用equals()呢?

当我们输入key的时候,map需要将传入的key与当前数组中存入的key相比较。

public class Main {
    public static void main(String[] args) {
        HashMap<String, String> map = new HashMap<>();
        map.put(new String("sss"),"hhh");
        map.put(new String("sss"), "aaa");
        // map里只有一个数据,因为String重写了equals方法,所以key属性值一样的会被覆盖
        System.out.println(map.size());
        HashMap<Person, String> map1 = new HashMap<>();
        map1.put(new Person("xiao",15), "ok");
        map1.put(new Person("xiao",15), "hao");
        // map1里有两个数据,明明key是一样的,却没有覆盖
        System.out.println(map1.size());
    }
}
class Person{
    String name;
    int age;
    Person(String name, int age){
        this.name = name;
        this.age = age;
    }
}
  • 添加重复的键值对:由于Map将不同的对象视为不同的键,如果我们使用相同类型的不同对象作为键,即使它们的属性值相同,Map也会将它们视为不同的键,从而导致添加重复的键值对。
  • 无法查找键值对:由于Map将不同的对象视为不同的键,如果我们使用一个对象作为键添加了一个键值对,而后又使用另一个对象作为键查找该键值对,那么Map会认为这两个对象是不同的键,因此无法找到对应的键值对。

因此,我们需要正确重写equals()方法。

hashcode()方法

HashMap为什么能通过key直接计算出value存储的索引。相同的key对象(使用equals()判断时返回true)必须要计算出相同的索引,否则,相同的key每次取出的value就不一定对。

map是通过hashcode()去寻找value数组索引的,所以还需要为对象覆写hashcode()方法。

public class Main {
    public static void main(String[] args) {
        HashMap<String, String> map = new HashMap<>();
        map.put(new String("sss"),"hhh");
        map.put(new String("sss"), "aaa");
        // map里只有一个数据,因为String重写了equals方法和hashcode方法,所以key属性值一样的会被覆盖
        System.out.println(map.size()); // 1
        HashMap<Person, String> map1 = new HashMap<>();
        Person p1 = new Person("xiao", 15);
        map1.put(p1, "ok");
        Person p2 = new Person("xiao", 15);
        map1.put(p2, "hao");
        // map现在也只有一个数据了,因为两个相同属性的对象被视作同一个
        System.out.println(map1.size()); // 1
    }
}
class Person{
    String name;
    int age;
    Person(String name, int age){
        this.name = name;
        this.age = age;
    }
    // 覆写equals方法
    @Override
    public boolean equals(Object o) {
        if (o instanceof Person p) {
            return this.name.equals(p.name) && this.age == p.age;
        }
        return false;
    }
    // 覆写hashcode方法
    @Override
    public int hashCode() {
        int h = 0;
        h = 31 * h + name.hashCode();
        h = 31 * h + age;
        return h;
    }
}

mapput方法里是用到了hash值的,因此不正确重写hash值而正确重写equals方法是没用的。

小节

比较基本数据类型或对象地址用==, 比较对象地址使用Objectequals方法, 比较对象属性值使用覆写之后的equals().

对于list集合数据类型,本质是数组,当存储对象数据类型的值时,重写equals方法才能使用contains()等需要使用equals进行比较的方法。

对于hash table类型的数据,必须覆写equals与hashcode方法,才能正常工作。

到此这篇关于Java ==,equals()与hashcode()的使用的文章就介绍到这了,更多相关Java ==,equals()与hashcode()内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java 线程池的实现方法

    java 线程池的实现方法

    在本篇文章里小编给大家整理了关于java 线程池的实现方法,有兴趣的朋友们可以学习参考下。
    2020-02-02
  • java类的全限定名是什么

    java类的全限定名是什么

    Java中的全限定名指的是包含包名和类名的完整标识,例如“java.lang.String”,而非限定名仅指类名,如“String”,全限定名用于区分不同包中相同名字的类,避免引用混淆,特别是在有多个包含相同类名的库时
    2024-09-09
  • 使用dom4j解析xml文件问题

    使用dom4j解析xml文件问题

    这篇文章主要介绍了使用dom4j解析xml文件问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-09-09
  • java随机数生成具体实现代码

    java随机数生成具体实现代码

    这篇文章主要为大家分享了java随机数生成具体实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-04-04
  • tio-boot jfinal-plugins框架整合redis示例详解

    tio-boot jfinal-plugins框架整合redis示例详解

    这篇文章主要为大家介绍了tio-boot jfinal-plugins框架整合redis示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-12-12
  • SpringMVC参数传递之基本数据类型和复杂对象说明

    SpringMVC参数传递之基本数据类型和复杂对象说明

    这篇文章主要介绍了SpringMVC参数传递之基本数据类型和复杂对象说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-10-10
  • 基于SpringCloud手写一个简易版Sentinel

    基于SpringCloud手写一个简易版Sentinel

    SpringCloud Alibaba Sentinel是当前最为流行一种熔断降级框架,简单易用的方式可以快速帮助我们实现服务的限流和降级,保证服务的稳定性。
    2021-05-05
  • Java实现导出word表格的示例详解

    Java实现导出word表格的示例详解

    这篇文章主要为大家详细介绍了如何利用Java语言导出word表格功能,文中的示例代码讲解详细,具有一定的借鉴价值,需要的小伙伴可以参考一下
    2022-12-12
  • 详解springSecurity之java配置篇

    详解springSecurity之java配置篇

    这篇文章主要介绍了详解springSecurity之java配置篇,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • SpringBoot项目nohup启动运行日志过大的解决方案

    SpringBoot项目nohup启动运行日志过大的解决方案

    这篇文章主要介绍了SpringBoot项目nohup启动运行日志过大的解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-05-05

最新评论