• HashCode 和 equals 学习笔记


    HashCode 和 equals

    hashCode 和 equals 用来标识对象,两个方法协同工作可以用来判断两个对象是否相等。根据生成的哈希码将数据离散开来,可以使存取数据更快。对象通过调用 Object.equals() 生成哈希值;由于不可避免地会存在哈希值冲突的情况,因此当 hashCode 相同时,还需要再调用 equal 进行一次值的比较;但是 hashCode 不同,直接判定 Objects 不同,跳过 equals ,这加快了冲突处理效率。 Object 类定义中对 hashCode 和 equals 要求如下:

    1. 如果两个对象的 equals 的结果是相等的,则两个对象的 hashCode 的返回结果也必须是相同的。

    2. 任何时候重写 equals ,都必须同时重写 hashCode。

    在 Map 和 Set 类集合中,用到这两个方法时,首先判断 hashCode 的值,如果 hash 相等,则再判断 equals 的结果,HashMap 的 get 判断代码如下:

    public V get(Object key) {
        Node<K,V> e;
        return (e = getNode(hash(key), key)) == null ? null : e.value;
    }
    
    //	而其中 getNode 方法中有一个判断如下
    
    if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
       		return e;
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    if 条件表达式中的 e.hash == hash 是先觉条件,只有相等才会执行后面的判断逻辑。如果不相等,后面的判断逻辑也就不会执行。equals 不相等时并不强制要求 hashCode 也不相等,但是哈希算法的初衷是尽可能让元素均匀分布,降低哈希冲突的概率,即在 equals 不相等时尽量使 hashCode 也不相等,这样 && 或 || 短路操作一旦生效,会极大地提高程序的执行效率。如果自定义对象作为 Map 的键,那么必须重写 hashCode 和 equals 。此外,因为 Set 存储的是也是不重复的对象,依据 hashCode 和 equals 进行判断,所以 Set 存储的自定义对象也必须重写这两个方法。而具体重写了 equals方法,但是没有重写 hashCode 方法,会有什么影响。下面通过实例来讲解下

    public class EqualsObject {
    
        private int id;
        private String name;
    
        public EqualsObject(int id, String name) {
            this.id = id;
            this.name = name;
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;	//	1
            if (o == null || getClass() != o.getClass()) return false;	// 2
            EqualsObject that = (EqualsObject) o;
            return id == that.id && Objects.equals(name, that.name);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    1 处先判断是否是统一对象,是的话直接返回 true

    2 处说明,首先判断两个对象的类型是否相同,如果不匹配,则直接返回 false。另外此处使用了 getClass 的方式,就是严格限制了只有 Eqauls 对象本身才可以执行 equals 操作。

    注意,上例代码中并没有重写 hashCode 方法,然后我们将上例对象加入到 HashSet 中测试下:

    在这里插入图片描述
    在这里插入图片描述

    最终输出的结果是3。但是这些 EqualsObject 对象明显是相同的,但是在 HashSet 中,应该只会存在一个。之所以结果为 3 ,是因为如果不重写 hashCode() ,即使 equals() 相等也毫无意义,Object.hashCode 的实现是默认为每一个对象生成一个不同的 int 数值,他本身是 native 方法,一般与对象的内存地址有关。

    关于重写equals尽量重写hashcode方法

    在没有重写 equals 方法时,我们直接调用的是 Object类里面的equals方法,这个方法比较的是两个对象的内存地址,如果通过new 关键字新建的两个对象,

    User user1 = new User("小明", "20", "湖南")User user2 = new User("小明", "20", "湖南")
    • 1
    • 2

    对应的属性都完全相同,但是它们分配的内存地址是不一样的,也就是属于不同的对象,因此调用这个方法时就是为false,但是明显不符合的我们想要的结果,在我们看来,这两个对象就是同一个对象,它们应该返回的是true。因此,想要让这两个对象相等,我们就需要重写 equals 方法。但是 hashCode 方法是根据内存来计算的,在保证这两个小明都是同一个人(同一对象)的前提下,它们对应的hashCode理应也应该是一样的,但是通过new关键字新建的对象对应的hashCode也明显不一样,这时候也需要我们重写hashCode方法,人为地返回true。

    例如用到map的时候,map是根据key的hashCode和key.equals是否都相等判断是否存在重复的entry的。所以如果我们从map中put进两个值(key都为 new User(“小明”, “20”, “湖南”) ),而没有重写hashCode,得到的结果(size = 2)和我们期望的结果(size=1)将不一样

    为什么Hashmap键值可以为null,而HashTable和ConcurrentHashMap不行?如果并发容器键值对可以为null 在多线程并发下哪个场景会有问题?

    在hashMap中,当存入一个key为username,值为null的数据时,调用了map.get(“username”),get() 方法的返回值时null。假设当前我们并不知道hashMap是否存在key为username的键值对,这时候我们需要有个方法来判断这个null到底是我们存进去的,还是这个key不存在而返回的null。在单线程的情况下下,我们通过contains方法来验证下

    if (map.contains("username")){
        return map.get("username");
    }
    
    • 1
    • 2
    • 3

    但是在ConcurrentHashMap或者HashTable中,如果允许键值都能为null,并且在多线程的情况下,当一个线程执行完 map.contains("username")时,其他一个线程已经把这个username的键值对给删掉了,这个时候我们通过get("username")得到其实是键值对不存在的null,而非我们存进去的key为username,值为null的null。

    如果键值不允许为null?假设当前有个键为username,值为xiaoming,执行到map.contains(“username”)时返回true,此时第二个线程进来把该键值对删除了,map.get(“username”)就会返回为null,而此时这个null就能很明确的表明该键不存在,而不是模棱两可(1.这个值就是null2.这个键不存在)

  • 相关阅读:
    PTA作业10单链表6-1 链表拼接
    Pinia(三)了解和使用state
    等保备案是什么意思?应该去哪里办理备案?
    阻抗与导纳的理解
    BGP——BGP基础概念
    经典Ubuntu20.04版本U盘安装双系统教程
    Java 基于Graphics2D 实现海报(支持自定义颜色,背景,logo,贴图)
    磁盘和文件系统管理(一)
    Rust初接触
    达梦数据库随系统开机自动启动脚本
  • 原文地址:https://blog.csdn.net/hyx1249273846/article/details/126397851