使用HashMap,如果key是自定义的类,就必须重写hashcode()和equals()
java编程里有关约定:如果两个对象根据equals方法比较是相等的,那么调用这两个对象的任意一个hashcode方法都必须产生相同的结果。
hashcode()和equals()都继承于object,在Object类中的定义为:
equals()方法在Object类中的定义:
public boolean equals(Object obj){
return (this == obj);
}
hashCode()的定义为:
public native int hashCode();
是一个本地方法,返回的对象的地址值。
1.hashcode()和equals()是在哪里被用到的?什么用的?
HashMap是基于散列函数,以数组和链表的方式实现的。
而对于每一个对象,通过其hashCode()方法可为其生成一个整形值(散列码),该整型值被处理后,将会作为数组下标,存放该对象所对应的Entry(存放该对象及其对应值)。
equals()方法则是在HashMap中插入值或查询时会使用到。当HashMap中插入 值或查询值对应的散列码与数组中的散列码相等时,则会通过equals方法比较key值是否相等,所以想以自建对象作为HashMap的key,必须重写 该对象继承object的equals方法。
2.本来不就有hashcode()和equals()了么?干嘛要重写,直接用原来的不行么?
HashMap中,如果要比较key是否相等,要同时使用这两个函数!因为自定义的类的hashcode()方法继承于Object类,其hashcode码为默认的内存地 址,这样即便有相同含义的两个对象,比较也是不相等的,例如,
Student st1 = new Student("wei","man");
Student st2 = new Student("wei","man");
正常理解这两个对象再存入到hashMap中应该是相等的,但如果你不重写 hashcode()方法的话,比较是其地址,不相等!
HashMap中的比较key是这样的,先求出key的hashcode(),比较其值是否相等,若相等再比较equals(),若相等则认为他们是相等 的。若equals()不相等则认为他们不相等。如果只重写hashcode()不重写equals()方法,当比较equals()时只是看他们是否为 同一对象(即进行内存地址的比较),所以必定要两个方法一起重写。
如果不被重写(原生)的hashCode和equals是什么样的?
不被重写(原生)的hashCode值是根据内存地址换算出来的一个值。
不被重写(原生)的equals方法是严格判断一个对象是否相等的方法(object1 == object2)。
为什么需要重写equals和hashCode方法?
在我们的业务系统中判断对象时有时候需要的不是一种严格意义上的相等,而是一种业务上的对象相等。在这种情况下,原生的equals方法就不能满足我们的需求了
所以这个时候我们需要重写equals方法,来满足我们的业务系统上的需求。那么为什么在重写equals方法的时候需要重写hashCode方法呢?
我们先来看一下Object.hashCode的通用约定(摘自《Effective Java》第45页)
在一个应用程序执行期间,如果一个对象的equals方法做比较所用到的信息没有被修改的话,那么,对该对象调用hashCode方法多次,它必须始终如一地返回 同一个整数。在同一个应用程序的多次执行过程中,这个整数可以不同,即这个应用程序这次执行返回的整数与下一次执行返回的整数可以不一致。
如果两个对象根据equals(Object)方法是相等的,那么调用这两个对象中任一个对象的hashCode方法必须产生同样的整数结果。
如果两个对象根据equals(Object)方法是不相等的,那么调用这两个对象中任一个对象的hashCode方法,不要求必须产生不同的整数结果。然而,程序员应该意识到这样的事实,对于不相等的对象产生截然不同的整数结果,有可能提高散列表(hash table)的性能。
如果只重写了equals方法而没有重写hashCode方法的话,则会违反约定的第二条:相等的对象必须具有相等的散列码(hashCode)
同时对于HashSet和HashMap这些基于散列值(hash)实现的类。HashMap的底层处理机制是以数组的方法保存放入的数据的(Node<K,V>[] table),其中的关键是数组下标的处理。数组的下标是根据传入的元素hashCode方法的返回值再和特定的值异或决定的。如果该数组位置上已经有放入的值了,且传入的键值相等则不处理,若不相等则覆盖原来的值,如果数组位置没有条目,则插入,并加入到相应的链表中。检查键是否存在也是根据hashCode值来确定的。所以如果不重写hashCode的话,可能导致HashSet、HashMap不能正常的运作、
如果我们将某个自定义对象存到HashMap或者HashSet及其类似实现类中的时候,如果该对象的属性参与了hashCode的计算,那么就不能修改该对象参数hashCode计算的属性了。有可能会移除不了元素,导致内存泄漏。
使用HashMap,如果key是自定义的类,就必须重写hashcode()和equals()的更多相关文章
- java集合框架(hashSet自定义元素是否相同,重写hashCode和equals方法)
/*HashSet 基本操作 * --set:元素是无序的,存入和取出顺序不一致,元素不可以重复 * (通过哈希值来判断是否是同一个对象) * ----HashSet:底层数据结构是哈希表, * 保证 ...
- HashMap中使用自定义类作为Key时,为何要重写HashCode和Equals方法
之前一直不是很理解为什么要重写HashCode和Equals方法,才只能作为键值存储在HashMap中.通过下文,可以一探究竟. 首先,如果我们直接用以下的Person类作为键,存入HashMap中, ...
- 关于HashMap自定义key重写hashCode和equals的问题
使用HashMap,如果key是自定义的类,就必须重写hashcode()和equals() hashcode()和equals()都继承于object,在Object类中的定义为: equals( ...
- python3.4中自定义数组类(即重写数组类)
'''自定义数组类,实现数组中数字之间的四则运算,内积运算,大小比较,数组元素访问修改及成员测试等功能''' class MyArray: '''保证输入值为数字元素(整型,浮点型,复数)''' de ...
- JAVA - 如果hashMap的key是一个自定义的类,怎么办?
JAVA - 如果hashMap的key是一个自定义的类,怎么办? 使用HashMap,如果key是自定义的类,就必须重写hashcode()和equals().
- Java用自定义的类型作为HashMap的key
需要重写hashCode()和equals()方法才可以实现自定义键在HashMap中的查找. public class PhoneNumber { private int prefix; //区 ...
- Java_map的key为自定义对象
首先自定义Key对象 import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; import java ...
- hashcode、equals、HashMap间的关系
1.从Object说起package com.hallo.collection; public class ObjectDemo { public static void main(String[] ...
- 当我们用自定义的类对象作为key时,我们必须在程序中覆盖HashCode()和equals()。
Key值既然可以作为对象,那么也可以用一个自定义的类.比如: m.put(new sutdent(“Liucy”,30),”boss”) 如果没有语句来判定Student类对象是否相同,则会全部打印出 ...
随机推荐
- C#反射技术的简单操作(读取和设置类的属性、属性值)
public class A { public int Property1 { get; set; } } static void Main(){ A aa = new A(); Type type ...
- 关于Excel 2016 总要点击两次才能打开的解决方法
1.快捷键:win+r,输入:regedit2.定位到如下项目“HKEY_CLASSES_ROOT\Excel.Sheet.12\shell\Open\command”:3.编辑原有的内容,在最后添加 ...
- 配置tomcat 加载指定的jar
# vi bin/catalina.sh
- [JAVA] maven 阿里云节点 settings.xml
<?xml version="1.0" encoding="UTF-8"?> <settings xmlns="http://mav ...
- 【计算机网络基础】URI、URN和URL的区别
先引用一张关系图 灰色部分为URI URI强调的是给资源标记命名,URL强调的是给资源定位. URI是Uniform Resource Identifier,表示是一个资源: URL是Uniform ...
- xorm -Alias,Asc,Desc方法实例
Alias(string)给Table设定一个别名 package main import ( "fmt" _ "github.com/go-sql-driver/mys ...
- 不一样的go语言-athens源码概览
前言 上一篇文章介绍了athens私服的安装以及vgo download protocol的简要介绍.本文着重介绍go proxy sever的实现原理以及athens是如何实现的. go get ...
- 使用 Angular RouteReuseStrategy 缓存(路由)组件
使用 Angular RouteReuseStrategy 缓存组件 Cache components with Angular RouteReuseStrategy RouteReuseStrate ...
- [高清] Spring揭秘完整高清版
------ 郑重声明 --------- 资源来自网络,纯粹共享交流, 如果喜欢,请您务必支持正版!! --------------------------------------------- ...
- (转)项目迁移_.NET项目迁移到.NET Core操作指南
原文地址:https://www.cnblogs.com/heyuquan/p/dotnet-migration-to-dotnetcore.html 这篇文章,汇集了大量优秀作者写的关于" ...