为什么要重写hashcode和equals方法?

为什么要重写hashcode和equals方法?

相信很多小伙伴被这个问题给困扰很久了,下面我就给大家详细说一下我的理解吧~

因为默认的equals方法是Object的方法,比较的是内存地址;而默认的hashcode方法返回的是对象的内存地址转换成的一个整数,实际上指的的也是内存,两个方法可以理解为比较的都是内存地址,这在实际开发的过程中在hashmap或者hashset里如果不重写的hashcode和equals方法的话会导致我们存对象的时候,把对象存进去了,取的时候却取不到想要的对象,这时候就需要重写这两个方法了,一般可以根据业务的需求来重写;

如果对象有名字和年龄这两个属性的话,最常见重写hashcode的方法是采用hash算法:      int hash=a*b+age/name;再将hash值返回。 

重写equals方法是认为在名字和年龄不为空的情况下,名字相等并且年龄也相等,那么就认为这是同一个对象。重写了hashcode和equals方法后我们就可以取得我们想要的值了,这样做保证了键值的唯一性,更有利于程序稳定。

因为重写了hashcode和equals方法可以迅速的在hashmap中找到键的位置;

Hashmap是通过hashcode来确定元素的下标的,具体的代码如下; int hash = hash(key.hashcode());  通过算出来的hash值,还有hashmap表的长度,可以确定元素在hashmap表中的下标,但是这种hash算法过于简单,会导致很多冲突发生,因为不同的key可以算出相同的hashcode,所以每个下标对对应的链表位置上会有很多的Entry对象,这时候就会通过key的equals方法在对应位置的链表中找到需要的元素,所以这个时候就需要重写equals方法,Hashmap的key可以是任何类型的对象,例如User这种对象,为了保证两个具有相同属性的user的hashcode相同,我们就需要改写hashcode方法,比方把hashcode值的计算与User对象的id关联起来,那么只要user对象拥有相同id,那么他们的hashcode也能保持一致了,这样就可以找到在hashmap数组中的位置了。如果这个位置上有多个元素,还需要用key的equals方法在对应位置的链表中找到需要的元素,所以只改写了hashcode方法是不够的,equals方法也是需要改写滴~当然啦,按正常思维逻辑,equals方法一般都会根据实际的业务内容来定义,例如根据user对象的id来判断两个user是否相等。 

对于两个对象,Java要求如下:

equals()相等,hashcode()一定相等;

quals()不等,hashcode()可能相等,也可能不等;

hashcode()不等,一定能推出equals()也不等;

hashcode()相等,equals()可能相等,也可能不等。

如果不重写hashcode和equals方法的话,放入相同的key时(特殊情况下),就不知道取哪一个。

举个例子:我们创建两个匿名的对象,当做key;new Person(“张三”); new Person(“张三”);

此时我们存放两个匿名对象是没有问题的,但取的这个作为key的匿名对象的时候就取不到了。输出结果会是null;

总结:重写hashcode方法和equals方法是为了程序运行更加稳定更加友好!

1.重写hashcode是为了保证相同的对象会有相同的hashcode;

2.重写equals是为了保证在发生冲突的情况下取得到Entry对象(也可以理解是key或是元素);

此文是一年前写的,当时可能理解得还不太正确,总结里的两点当时说得没错,但是不太好理解;

重写hashcode和equals方法的原因有两个:

1、因为 在hashmap中不论是put还是get操作会用到这两个方法;

2、Java规范的约定,在集合类中需要重写这两个方法;

我这篇博客说得比较清楚;点这里

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏章鱼的慢慢技术路

C++笔试面试题整理

封装来源于信息隐藏的设计理念,是通过特性和行为的组合来创建新数据类型让接口与具体实现相隔离。

9143
来自专栏大闲人柴毛毛

稳扎稳打JavaScript(一)——作用域链内存模型

几个概念 在开始之前,先了解几个概念。 1.1. 作用域 作用域是指当前正在执行的代码能够访问到变量的范围; 每个函数都有各自的作用域,存储函数所有的局部变量...

4538
来自专栏Python爬虫实战

Python数据类型之字典(上)

之前系列文章介绍了Python简单数据类型和序列数据类型,本文来学习一种新的映射数据类型:字典。

871
来自专栏逆向技术

C语言_第二讲_规范以及常用数据类型

一丶编码规范基本数据类型 编码规范 任何程序员,都应该有良好的的编码习惯,便于以后的代码可读性和维护 常见了编码规范有 匈牙利命名法 驼峰式大小写 匈牙利命名法...

2460
来自专栏Java编程

Java泛型详解

Java泛型(generics)是JDK 5中引入的一个新特性,允许在定义类和接口的时候使用类型参数(type parameter)。声明的类型参数在使用时用具...

7050
来自专栏aCloudDeveloper

C++中引用详解

引用简介   引用就是某一变量(目标)的一个别名,对引用的操作与对变量直接操作完全一样。   引用的声明方法:类型标识符 &引用名=目标变量名;   【...

1845
来自专栏一个爱吃西瓜的程序员

每天学习一点儿算法--选择排序

很多算法只有在数据经过排序后才管用,比如我们之前学习的二分查找。当然,很多语言都内置了排序算法,比如Python中的sort()函数和sorted()函数。我们...

2959
来自专栏古时的风筝

模板的简单介绍与使用

什么是模板? 模板(template)指c++中的函数模板与类模板,大体对应于C#和Java众的泛型的概念。目前,模板已经成为C++的泛型编程中不可缺少的一部分...

1838
来自专栏JetpropelledSnake

Python入门之迭代器/生成器/yield的表达方式/面向过程编程

 本章内容     迭代器     面向过程编程       一、什么是迭代       二、什么是迭代器       三、迭代器演示和举例       四、生...

2919
来自专栏WD学习记录

数据结构与算法2016-06-03

一个算法调用自己来完成它的部分工作,在解决某些问题时,一个算法需要调用自身。如果一个算法直接调用自己或间接调用自己,就称这个算法是递归的。根据调用方式的不同,它...

802

扫码关注云+社区

领取腾讯云代金券