equals()和hashCode()是Object类的两个函数,重要性可见一斑,不过我们平时使用却未必能深入理解他们。本文从java doc触发,讲到它们与哈希表的关系,再到具体的实现,就我目前掌握的关于这两个函数进行一个梳理。

  一、Java Doc

  Java doc其实远不是只有在编程时查阅API才有用,很多时候它体现了Java的一些设计理念,当然这些理念需要好好分析才能理解。两个函数的具体doc文本可查,不予罗列,只说说重点:

  1. equals():

  a)该方法是在非空对象引用上实现相等关系,具有自反性、对称性、传递性和一致性。这里需要注意“非空”这个词,这说明,任何非空对象不可能equals一个空对象(null),在重写equals的时候,这一点很重要,不然极有可能NullPointerException。

  b)当equals函数被重写时通常有必要重写hashCode()函数,以维护hashCode() 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。这句话很抽象,后面解释。

  2. hashCode():

  a)支持此方法是为了提高哈希表的性能。这说明,该函数从设计上来说就是为了给哈希表使用的!

  b)hashCode协定,简而言之:如果用于equals比较的信息没有更改,那么hashCode必须返回相同的值;如果两个对象是equals的,那么hashCode必须相同;如果两个对象根据equals不等,那么它们hashCode也可以相等,只是不等的hashCode可以提高哈希表性能。

  二、Map、HashMap、HashSet等

  这几个数据结构与上述两个函数之间有非常重要的关系。以Set为例,Set中不能由相同的元素,因此比较就是用equals函数。也就是说,从通常的业务逻辑上来讲,要使用Set,就要重写equals函数,否则会出问题。Map类似。以如下类为例:

  

public class Student{
public int stuId;
public String stuName;
public boolean gender; public Student(int id,String name,boolean g)
{
stuId=id;
stuName=name;
gender=g;
} public static void main(String[] args)
{
Student stu1=new Student(123,"Tom",true);
Student stu2=new Student(123,"Tom",true);
System.out.println(stu1.equals(stu2));
}
}

  从业务逻辑上来讲,我们希望上述输出true,但事实上输出false。因此必须重写equals函数,如下:

    @Override
public boolean equals(Object o){
if(o==null)
return false;
if(o==this)
return true;
if(o.getClass!=getClass())
return false;
Student s=(Student) o;
return (stuId==e.stuId);
}

  但是加入上述代码仍然不够,假如main函数中有如下代码:

    public static void main(String[] args)
{
Student stu1=new Student(123,"Tom",true);
Student stu2=new Student(123,"Tom",true);
Set<Student> students=new HashSet<Student>();
students.add(stu1);
students.add(stu2);
System.out.println(students);
}

  我们是希望students中只有一个对象(Set的定义),然而输出了两个对象。问题何在?问题就在于HashSet的工作流程:为了提高效率,HashSet先通过计算hashCode得到对象应该插入的位置,如果该位置为空,就插入;如果该位置不为空,则比较新插入对象和已有对象是否equals,如果equals返回true,就不插入,如果返回false,则说明发生了冲突,使用解决冲突策略并把新对象插入。上述代码没有重写hashCode函数,两个对象返回不同的hashCode,插入时对应位置都是空的,直接插入了对象,换言之,Set中包含了两个equals返回true的对象,这违反了Set的定义,将给函数带来不可想象的后果。因此必须重写hashCode函数:

  

    @Override
public int hashCode()
{
final int PRIME=31;
int result=1;
result=PRIME*result+stuId;
return result;
}

  回过头看doc的说明:根据equals不相等的对象,其hashcode不一定非要不同(也即可以相同)。结合HashSet的工作流程,如果他们的hashcode相同,此时必然冲突,但是可以解决冲突后插入,所以不违反Set的定义但是却会影响性能。

  三、如何重写HashCode

  《Effective Java》中有介绍一种简单方法,具体不列,主要思想是使用所有参与equals比较的变量都与某个素数进行计算,使得不同对象计算出来尽量不同而且分散,这样可以减少冲突。关于此的博客网上很多,暂不作复述,待理解更深刻时整理。

  

关于equals和hashCode的更多相关文章

  1. How to implement equals() and hashCode() methods in Java[reproduced]

    Part I:equals() (javadoc) must define an equivalence relation (it must be reflexive, symmetric, and ...

  2. JAVA中用堆和栈的概念来理解equals() "=="和hashcode()

    在学习java基本数据类型和复杂数据类型的时候,特别是equals()"=="和hashcode()部分时,不是很懂,也停留了很长时间,最后终于有点眉目了. 要理解equals() ...

  3. 关于equals、hashcode和集合类的小结

    一.首先明确一点:equals()方法和hashcode()方法是Object类里的方法. 查看源码可以知道,在Object类中equals(obj)方法直接返回的是  this == obj 的值. ...

  4. Object方法equals、hashCode

    java知识背景: 1)hashCode()方法返回的是Jvm的32位地址 2)==比较的是对象在jvm中的地址 3)Object的equals()比较的就是jvm物理地址 4)比较2个对象使用equ ...

  5. Java中的equals和hashCode方法

    本文转载自:Java中的equals和hashCode方法详解 Java中的equals方法和hashCode方法是Object中的,所以每个对象都是有这两个方法的,有时候我们需要实现特定需求,可能要 ...

  6. Java提高篇——equals()与hashCode()方法详解

    java.lang.Object类中有两个非常重要的方法: 1 2 public boolean equals(Object obj) public int hashCode() Object类是类继 ...

  7. Java中==、equals、hashcode的区别与重写equals以及hashcode方法实例(转)

    Java中==.equals.hashcode的区别与重写equals以及hashcode方法实例  原文地址:http://www.cnblogs.com/luankun0214/p/4421770 ...

  8. java中equals和hashCode方法的解析

    解析Java对象的equals()和hashCode()的使用 前言 在Java语言中,equals()和hashCode()两个函数的使用是紧密配合的,你要是自己设计其中一个,就要设计另外一个.在多 ...

  9. Java实战equals()与hashCode()

    一.equals()方法详解 equals()方法在object类中定义如下: 代码 public boolean equals(Object obj) { return (this == obj); ...

  10. 一次性搞清楚equals和hashCode

    前言 在程序设计中,有很多的“公约”,遵守约定去实现你的代码,会让你避开很多坑,这些公约是前人总结出来的设计规范. Object类是Java中的万类之祖,其中,equals和hashCode是2个非常 ...

随机推荐

  1. Hbase之更新单条数据

    import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.HBaseConfiguration; impo ...

  2. android 内存泄露之jni local reference table overflow (max=512)

    在android项目中要实现一个需求 为了性能的要求只能用c代码来实现功能. 这样就牺牲了java跨平台性. 通过加载.so的方式,把用c实现的模块集成到app中. android提供jni层,作为一 ...

  3. jmeter 构建一个LDAP测试计划

    添加用户 第一步你想做的每一个JMeter测试计划是添加一个线程组元素. 线程组告诉JMeter的用户数量你想模拟,用户应该发送的次数 请求,他们应该发送的请求的数量. 继续添加ThreadGroup ...

  4. GetMemory

    在函数中动态申请内存(虚拟内存,堆),利用指针返回值指向申请的内存.

  5. poj-----(2528)Mayor's posters(线段树区间更新及区间统计+离散化)

    Mayor's posters Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 43507   Accepted: 12693 ...

  6. 149. Max Points on a Line *HARD* 求点集中在一条直线上的最多点数

    Given n points on a 2D plane, find the maximum number of points that lie on the same straight line. ...

  7. 下载模板,上传EXCEL

    说道SAP里对EXCEL操作的大概就是上传,下载,显示了... 下载:(文档是通过SMW0上传的)注:如果下载的时候需要填充EXCEL的值,...请参考另一篇文档,OLE CALL METHOD CL ...

  8. 转:Vmware Exsi使用简要说明

    界面介绍 Exsi的管理工具可以用vSphere Client来管理虚拟机.管理虚拟的网络交换机.管理物理机的内存.物理机的硬盘.物理机的CPU等资源.界面的大致介绍如下图. 资源分配 创建内存.CP ...

  9. Windows 下对目录建立软链接

    在Linux下,可以很方便的通过ln命令创建对文件和对文件夹的软链接.在Windows下,通过快捷方式,可以创建到文件和文件夹的链接,但是这软链接不是一个层面的上东西.软链接是底层文件系统层面的,而快 ...

  10. X61的intel wireless 3945abg 不再掉线了

    X61本的3945ABG无线网卡总是用一段时间就掉一次线(大约一个小时不到),换过两个路由器都这毛病. 今天有空,查了下,把网卡的“节约电源”去掉了,照样掉. 升级了驱动,掉的更勤了. 调整无线通道, ...