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. jquery 获取鼠标位置

    //获取鼠标位置 $(function(){ $('body').mousemove(function(e) { e = e || window.event; __xx = e.pageX || e. ...

  2. linux 后台执行命令

    本文主要内容: 1. 设置ctontab文件,并用它来提交作业. 2. 使用at命令来提交作业. 3. 在后台提交作业. 4. 使用nohup命令提交作业. 名词解释: cron 系统调度进程.可以使 ...

  3. Hbase之批量数据写入

    /** * Created by similarface on 16/8/16. */ import java.io.IOException; import org.apache.hadoop.con ...

  4. windows redis:Uncaught exception 'RedisException' with message 'Redis server went away'

    window-exe-redis-2.8.12服务,当你复制好php_igbinary.dll,php_redis.dll时候,你运行redis报错:Fatal error: Uncaught exc ...

  5. mysql数据库回滚

    在应用$mysqli时,因没常用到数据回滚,老忘,整理下,做个记录. $mysqli->autocommit(FALSE);//自动提交设置关闭 $mysqli->query(" ...

  6. 队列 - 从零开始实现by C++

    参考链接:数据结构探险-队列篇 数据结构太重要了,不学好是没法进行软件开发的. C++写数据结构基本套路:一个.h文件写该数据结构类的接口:一个.cpp文件写接口的具体实现:一个main.cpp用于测 ...

  7. js setTimeout 与 setInterval 以及 for 循环 刷新UI

    1. setTimeout() 方法用于在指定的毫秒数后调用函数或计算表达式:执行一次: 如果需要执行多次,自身再次调用 setTimeout(): 示例:无穷循环并带停止按钮的 <html&g ...

  8. Working with Data » Getting started with ASP.NET Core and Entity Framework Core using Visual Studio » 排序、筛选、分页以及分组

    Sorting, filtering, paging, and grouping 7 of 8 people found this helpful By Tom Dykstra The Contoso ...

  9. 关于ASP.NET与CLR相互关系的一些总结

    原文地址:http://www.cnblogs.com/jasenkin/archive/2010/10/20/asp-net-clr-relation.html CLR(COM服务器) CLR作为一 ...

  10. selenium+python笔记6

    #!/usr/bin/env python # -*- coding: utf-8 -*- """ @desc: 将登陆动作封装成function "" ...