java基础 equals与hashCode

Java中equals相关

equals()与==的关系

==:它是一个操作符,作用是判断两个对象的地址是否相等

基础类型比较的是值,引用类型比较的是内存地址

equals()

  • 类未覆盖equals()方法,则调用Object类提供的equals(),等价于通过“==”进行比较
  • 类覆盖equals()方法,为了比较两者内容是否相等,如相等则返回true

equals()即使被覆盖,通常第一步也是利用"=="进行判断,若为false,再根据不同类型对值进行判断

举例

 public static void main(String[] args) {
       String var1 = new String("asd");
       String var2 = new String("asd");
       String var3 = "asd";
       String var4 = "asd";
        System.out.println(var1.equals(var2));
        System.out.println(var1 == var2);
        System.out.println(var1 == var3);
        System.out.println(var3 == var4);
    }

输出
在这里插入图片描述
说明:

从上面,可以看到String类重写了equals(),因为它可以判断字符串内容是否相等返回true或false。
同时,可以注意到,String类有两种实例化方式,及直接赋值和new,new方法是直接在堆中创建一个对象,而String的赋值先检查常量池中是否有相同的字符串常量,如果有则让String变量指向此字符串常量地址,否则在常量池中创建一个字符串常量。
所以,看到String直接赋值的变量比较地址时是返回true的

equals()和hashCode()

首先,我们要记住,不管是否运用到Key-Value集合中,重写equals()一定要重写hashCode(),因为这是一个设计规范,你永远不知道这个类型未来是否会运用到Key-Value中。记住之后,下面我们来详细讲解原理上的原因

hashCode()介绍

  1. hashCode()的作用是获取哈希码(散列码),返回类型是一个整数。哈希码是用来获取对象在哈希表的索引位置的(如,在hashMap中就是利用哈希码与哈希表(数组结构)的长度的取模运算得到索引位置)。
  2. hashCode()是定义在Object.java中,及所有类都包含它。它主要在类充当散列表类(hashMap,hashtable)中Key值或散列表类(hashSet)中元素时,起到判重的作用。

hashCode()的意义

比如在HashSet集合中,由于其不可重复特性,在检测重复时,利用率hashCode
当你把对象加入 HashSet 时,HashSet 会先计算对象的 hashcode 值来判断对象加入的位置,同时也会与该位置其他已经加入的对象的 hashcode 值作比较,如果没有相符的 hashcode,HashSet 会假设对象没有重复出现。但是如果发现有相同 hashcode 值的对象,这时会调用 加入对象所属类中的equals()方法来检查加入对象和集合中 hashcode 相等的对象是否真的相同。如果两者相同,HashSet 就不会让其加入操作成功。这样可以在equals()之前先判断一次,及筛选一次,减少equals()b比较次数,提高效率。
HashSet是基于HashMap实现的其判重操作也是调用的HashMap中put()

hashCode()和equals()的关系

从逻辑上讲,相等对象的哈希值一定相等,同时由于不相等对象的哈希值也可能相同及哈希碰撞。所以我们可以得到一个一般规律:当对象,equals()相等时,hashCode()返回值一定相等,equals()不等时,hashCode()不一定不等。

所以,在类被应用到散列表类型时(HashMap,Hashtable,HashSet),我们希望可以通过相等的对象获取到对于的value和相等的对象在HashSet集合中不重复,及equals()相等的对象,在散列表中只存在一个。
如果重写equals()不重写hashCode():默认会调用Object.java中的本地方法hashCode(),这会导致,在equals()判断相等的两个对象,哈希码不同,从而与我们希望的逻辑结果不同。

举例

创建一个User类,分两次实验

  1. 重写hashCode()
  2. 不重写hashCode()
public class User {
    private String name;
    private int  hash;
    public User(String name) {
        this.name = name;
    }
    @Override
    public boolean equals(Object obj) {
        // return super.equals(obj);
        // if (obj.getClass().equals(User.class)) {}
        if (obj instanceof User) {
            User c = (User) obj;
            return name == c.name;
        }
        return false;
    }
    @Override
    public int hashCode(){
        return Objects.hash(name);
    }
}

执行的主方法类

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

        User user1 = new User("李一");
        User user2 = new User("李一");

        System.out.println("user1.hashCode())>>>"+ user1.hashCode());
        System.out.println("user2.hashCode())>>>"+ user2.hashCode());
        HashMap<User ,String>map = new HashMap<>();
        map.put(user1,"李一");

        System.out.println("Key>>user1  "+map.get(user1));
        System.out.println("Key>>user2  "+map.get(user2));



    }

}

运行结果

第一次:不重写hashCode()
在这里插入图片描述
第二次:重写hashCode()
在这里插入图片描述
说明:

  • 重写的hashCode()中,调用了Objects类中的hash(value),其功能是根据参数通过某种哈希函数产生哈希码,这里是根据name产生哈希码

分析

可以发现,两次执行的结果中,前者未重写hashCode(),对象相等,但是哈希值不相等,导致在HashMap中相当于两个不同的key,无法通过相等对象获取value。而重写后hashCode()则实现了期望。

总结

  1. equals()与操作符==的关系
    简单的说
    • equals()经过重写后要达到判断值相等的功能
    • 操作符==:是判断引用类型地址的是否相等以及基础类型(byte,int,short,long,char,double,float,char,boolean)的值是否相等的
  2. equals()与hashCode的关系
    • hashCode()返回整数,及哈希值,它是定义在Object.java中的
    • 重写equals()必要重写hashCode(),因为在类被用于散列表中时,不重写hashCode()会导致equals()相等的对象在散列表中被认为是不同的。

我要在最后重复一遍的是:有人可能会认为只要不将该类用在散列表类型中就不需要在重写equals()情况下重写hashCode(),当然从执行上来说是这样没错,但是为了代码的可扩展性安全性来讲,是有问题的,因为你无法预料到未来是否会将其用到散列表中。所以在日常编程中,严格遵守设计规范是有必要的。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值