java通用方法equals、hashcode的重写注意事项

2023-05-16

最近在读effictive java这本书,看到关于java通用方法重写时的某些规则,又想起项目中重写bean的equals方法,仔细一想确实有很多不正确的地方,所幸项目中的那个对象使用频率低没有出现问题。结合看hashmap的源码时发现读取写入方法与equals,hashcode密切相关,为了不秒忘记,在这记录一下。

equals和hashcode本来都只是object的方法,如果不进行重写,那么equals源码实际上是==比较,比较的是两个对象的地址,除非是同一个对象,否则均为false.

例:public boolean equals(Object obj) {
        return (this == obj);
    }
    而我们经常使用的类库,如String、Character等都是对其进行重写后,有自己相等的逻辑,如String即所有字母相同视为equals.
public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String) anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                            return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }
 hashcode也是如此,object的hashcode返回的也是和对象地址相关的值,而重写时是根据类的字段有很多规则,在此暂时不深究。但hashcode与equals之间有几个约定规则。
    1.如果两个对象通过equals方法判定相等,则他们的hashcode必须相等。
    2.反之,如果两个对象有相同的hashcode,却并不一定equals。
    3.对同一个对象,无论其内部属性如何改变,应该返回相同的hashcode。
    一开始我不太理解这些规则,我想我自己在写一个类时即使不这么做你又能耐我何呢?...
    知道我在使用集合类库时得不到正确的结果时我懂了,其实这都是为集合类库做准备,因为我们平时一般操作多个对象都是通过集合类库啊。比如想查看下某个对象的Index
public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }
 显然是用equals查找对象,如果没有重写对象的equals方法,就会调用父类object的equals方法,即为==比较,如果new people("zhangshan"),然后再indexOf(new people("zhangshan"))则会返回-1似乎找不到zhangshan这个刚刚加进去的对象。去年刚毕业时面试似乎还被问到这个问题,当时还不服的觉得是混淆视听,其实是对基本方法的理解不够。
    在说hashcode,其实是为hash算法而生,诸如hashset,hashmap,hashtable等,其实看他们的源码会理解的十分深刻。
public V put(K key, V value) {
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key);
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }


        modCount++;
        addEntry(hash, key, value, i);
        return null;
    }
 首先判断是根据key的hashcode生成hash值,然后根据这个值和数组长度得到其数组下表,即其即将要插入的位置。这里其实包含了很多东西,首先hashcode如果为了方便都返回一样的值,那么所有的键值对都将装在一个桶中,hashmap即退化为普通链表。而如果对象的hashcode不满足上面的第一点,即相同对象hashcode却不同则会导致其在桶中的位置不同,即会造成重复的键,已经不符合map的原则。而hashcode由于是由计算产生,尽管算法尽量避免重复,但当然有重复的可能,所以并不能由此说明两对象equals,此时则会在桶中的相同位置即链表中加入数据。对于第三点是显而易见,如果一个对象仅仅是由于属性值发生变化,hashcode就发生变化,那就根本无法确定它作为键时在桶里位置,也就根本找不到对应的值了,都没机会做equals比较了,如下。
final Entry<K,V> getEntry(Object key) {
        if (size == 0) {
            return null;
        }


        int hash = (key == null) ? 0 : hash(key);
        for (Entry<K,V> e = table[indexFor(hash, table.length)];
             e != null;
             e = e.next) {
            Object k;
            if (e.hash == hash &&
                ((k = e.key) == key || (key != null && key.equals(k))))
                return e;
        }
        return null;
    }

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java通用方法equals、hashcode的重写注意事项 的相关文章

随机推荐

  • 利用python画图

    因为最近论文收尾需要画图 xff0c 于是学了一些画图的东西在这里分享一下 一 环境配置 linux ubuntu 下需安装下面三个包 xff1a Numpy Scipy Matplotlib 分别输入下面的代码进行安装 xff1a 二 开
  • Python实现冒泡排序

    冒泡排序顾名思义就是整个过程就像气泡一样往上升 xff0c 单向冒泡排序的基本思想是 xff08 假设由小到大排序 xff09 xff1a 对于给定的n个记录 xff0c 从第一个记录开始依次对相邻的两个记录进行比较 xff0c 当前面的记
  • 详解贪心算法(Python实现贪心算法典型例题)

    贪心算法 贪心算法 xff08 又称贪婪算法 xff09 是指 xff0c 在对问题求解时 xff0c 总是做出在当前看来是最好的选择 也就是说 xff0c 不从整体最优上加以考虑 xff0c 他所做出的是在某种意义上的局部最优解 贪心算法
  • 详解动态规划算法(Python实现动态规划算法典型例题)

    动态规划 xff08 Dynamic programming xff09 是一种在数学 计算机科学和经济学中使用的 xff0c 通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法 动态规划算法是通过拆分问题 xff0c 定义问题状态
  • CNN卷积神经网络训练时占多少显存(GPU)的计算

    以前总看见别人说某某神经网络参数量有多少 xff0c 大概占用多大的显存等等描述 xff0c 但心里却并不知道为什么是这么多 xff0c 今天看到这篇文章 xff0c 大体上有了一定的理解 参数量的计算 xff1a VGG Network
  • JS编写的科学计算器

    文章为原创 xff0c 转载请注明出处 xff0c 谢谢支持 xff01 进阶版代码地址 xff1a https github com Summer Dong calculator 在此版本中使用了Angular框架和Boostrap xf
  • 安装使用JPEG库遇到的问题(用于交叉编译)

    使用JPEG 官方解码库时出现的问题 xff1a 使用example c 接口编译时 xff1a 1 错误 ubuntu mnt hgfs GZ1961 linux系统文件IO day15 newjpeg gcc main c exampl
  • TP4056 充电电路学习借鉴

    最近计划的一个 DIY 项目有安排充放电锂电池 xff0c 于是搜集了两个比较相似的方案 xff0c 借鉴学习一下 一 TP4056单节锂电池充电板设计方案 原理图 43 源码 顺带说 xff0c 电路城 这个网站还是比较有意思的 xff0
  • WSL2 安装 GUI,并使用 XRDP实现连接(内含汉化操作)

    效果图 随着 wsl2 的发布 xff0c wsl 已经从玩具变成了一个实用的开发利器 xff0c 从最新的微软开发者博客对 wsl 的路线发展规划 xff0c 未来 wsl 将会支持 GPU 计算和 GUI xff08 点此了解详情 xf
  • V4L2打开video设备注意(读写权限)

    V4L2编程中在open 34 dev video 34 时应注意 xff1a 摄像头采集到的数据是最开始是存储在内核空间我们申请的缓冲区中的 xff0c 具体设置如下 xff1a req count 61 5 req type 61 V4
  • mysql 分组取最新的一条记录(整条记录)

    mysql取分组后最新的一条记录 下面两种方法 一种是先筛选 出最大和最新的时间 在连表查询 一种是先排序 然后在次分组查询 默认第一条 就是最新的一条数据了 xff08 此条错误 xff0c 分组mysql官方文档说明 是随机选择分组的一
  • 数据结构:回文判断

    7 1 回文判断 回文是指正读反读均相同的字符序列 xff0c 如 abba 和 abdba 均是回文 xff0c 但 good 不是回文 编写一个程序 xff0c 使用栈判定给定的字符序列是否为回文 输入格式 输入待判断的字符序列 xff
  • Proxmox VE /Debian /Ubuntu 设置合上笔记本盖子不休眠的方法

    书接上回和上上回 众所周知 xff0c 服务器是没有AB面的 xff08 KVM当然不算了 xff09 xff0c 燃鹅笔记本有 xff0c 不能让屏幕一直打开亮着吧 xff0c 但是默认都是关闭盖子休眠 xff0c 咋办呢 i i xff
  • 实例解说Linux中fdisk分区使用方法

    实例解说Linux中fdisk分区使用方法 一 fdisk 的介绍 xff1b fdisk Partition table manipulator for Linux xff0c 译成中文的意思是磁盘分区表操作工具 xff1b 本人译的不太
  • ROS 新建py项目并添加话题发布

    目录 一 ros下新建py项目 二 调试运行代码 三 新建话题订阅 发布 一 ros下新建py项目 1 建立工作空间 mkdir ros workspace cd ros workspace mkdir src 2 初始化工作空间 cd到r
  • CCF认证期末预测之最佳阈值

    期末预测之最佳阈值 题目描述 具体来说 xff0c 顿顿评估了 m m m 位同学上学期的安全指数 xff0c 其中第 i 1
  • CCF元素选择器

    思路 fat数组保存其直接祖先 include lt bits stdc 43 43 h gt using namespace std const int maxn 61 105 int n m fat maxn dot maxn stri
  • ICU4C 介绍: C/C++ 平台强大的国际化应用开发组件

    ICU4C 介绍 C C 43 43 平台强大的国际化应用开发组件 荣 施李 shilirong 64 gmail com 软件工程师 EMC 简介 xff1a 随着全球经济快速一体化 xff0c 信息的国际化成为了当前热门的话题 xff0
  • Java数据类型的转换:隐式(自动)转换与强制转换

    一 数据类型的分类 Java 中数据类型分为基本数据类型及引用数据类型 Java 数据类型的转换一般分三种 xff0c 分别是 xff1a 简单数据类型之间的转换 xff1b 字符串与其它数据类型的转换 xff1b 其它实用数据类型转换 二
  • java通用方法equals、hashcode的重写注意事项

    最近在读effictive java这本书 xff0c 看到关于java通用方法重写时的某些规则 xff0c 又想起项目中重写bean的equals方法 xff0c 仔细一想确实有很多不正确的地方 xff0c 所幸项目中的那个对象使用频率低