以下内容总结自《Effective Java》。
1.何时需要重写equals()
当一个类有自己特有的“逻辑相等”概念(不同于对象身份的概念)。
2.设计equals()
[1]使用instanceof操作符检查“实参是否为正确的类型”。
[2]对于类中的每一个“关键域”,检查实参中的域与当前对象中对应的域值。
[2.1]对于非float和double类型的原语类型域,使用==比较;
[2.2]对于对象引用域,递归调用equals方法;
[2.3]对于float域,使用Float.floatToIntBits(afloat)转换为int,再使用==比较;
[2.4]对于double域,使用Double.doubleToLongBits(adouble) 转换为int,再使用==比较;
[2.5]对于数组域,调用Arrays.equals方法。
3.当改写equals()的时候,总是要改写hashCode()
根据一个类的equals方法(改写后),两个截然不同的实例有可能在逻辑上是相等的,但是,根据Object.hashCode方法,它们仅仅是两个对象。因此,违反了“相等的对象必须具有相等的散列码”。
4.设计hashCode()
[1]把某个非零常数值,例如17,保存在int变量result中;
[2]对于对象中每一个关键域f(指equals方法中考虑的每一个域):
[2.1]boolean型,计算(f ? 0 : 1);
[2.2]byte,char,short型,计算(int);
[2.3]long型,计算(int) (f ^ (f>>>32));
[2.4]float型,计算Float.floatToIntBits(afloat);
[2.5]double型,计算Double.doubleToLongBits(adouble)得到一个long,再执行[2.3];
[2.6]对象引用,递归调用它的hashCode方法;
[2.7]数组域,对其中每个元素调用它的hashCode方法。Arrays.hashCode(...)只会计算一维数组元素的hashCOde,如果是多维数组,那么需要递归进行hashCode的计算,那么就需要使用Arrays.deepHashCode(Object[])方法。
[3]将上面计算得到的散列码保存到int变量c,然后执行 result=37*result+c;
[4]返回result。
 
为什么每次需要使用乘法去操作result? 
主要是为了使散列值依赖于域的顺序,还是上面的那个例子,Test t = new Test(1, 0)跟Test t2 = new Test(0, 1), t和t2的最终hashCode返回值是不一样的。
为什么是31? 31是个神奇的数字,因为任何数n * 31就可以被JVM优化为 (n << 5) -n,移位和减法的操作效率要比乘法的操作效率高的多。
我们应该先了解java判断两个对象是否相等的规则。
在java的集合中,判断两个对象是否相等的规则是: 
首先,判断两个对象的hashCode是否相等
如果不相等,认为两个对象也不相等
如果相等,则判断两个对象用equals运算是否相等 
如果不相等,认为两个对象也不相等 
如果相等,认为两个对象相等
我们在equals方法中需要向下转型,效率很低,所以先判断hashCode方法可以提高效率
如何重写hashCode方法呢?
5.示例
下面的这个类遵循上面的设计原则,重写了类的equals()和hashCode()。
package com.zj.unit;
import java.util.Arrays;
 
public class Unit {
    private short ashort;
    private char achar;
    private byte abyte;
    private boolean abool;
    private long along;
    private float afloat;
    private double adouble;
    private Unit aObject;
    private int[] ints;
    private Unit[] units;
 
    public boolean equals(Object o) {
       if (!(o instanceof Unit))
           return false;
       Unit unit = (Unit) o;
       return unit.ashort == ashort
              && unit.achar == achar
              && unit.abyte == abyte
              && unit.abool == abool
              && unit.along == along
              && Float.floatToIntBits(unit.afloat) == Float
                     .floatToIntBits(afloat)
              && Double.doubleToLongBits(unit.adouble) == Double
                     .doubleToLongBits(adouble)
              && unit.aObject.equals(aObject)
&& equalsInts(unit.ints)
              && equalsUnits(unit.units);
    }
 
    private boolean equalsInts(int[] aints) {
       return Arrays.equals(ints, aints);
    }
 
    private boolean equalsUnits(Unit[] aUnits) {
       return Arrays.equals(units, aUnits);
    }
 
    public int hashCode() {
       int result = 17;
       result = 37 * result + (int) ashort;
       result = 37 * result + (int) achar;
       result = 37 * result + (int) abyte;
       result = 37 * result + (abool ? 0 : 1);
       result = 37 * result + (int) (along ^ (along >>> 32));
       result = 37 * result + Float.floatToIntBits(afloat);
       long tolong = Double.doubleToLongBits(adouble);
       result = 37 * result + (int) (tolong ^ (tolong >>> 32));
       result = 37 * result + aObject.hashCode();
       result = 37 * result + intsHashCode(ints);
       result = 37 * result + unitsHashCode(units);
       return result;
    }
 
    private int intsHashCode(int[] aints) {
       int result = 17;
       for (int i = 0; i < aints.length; i++)
           result = 37 * result + aints[i];
       return result;
    }
 
    private int unitsHashCode(Unit[] aUnits) {
       int result = 17;
       for (int i = 0; i < aUnits.length; i++)
           result = 37 * result + aUnits[i].hashCode();
       return result;
    }
}

hashCode之二--Java:重写equals()和hashCode()的更多相关文章

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

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

  2. Java:重写equals()和hashCode()

    Java:重写equals()和hashCode() 1.何时需要重写equals() 当一个类有自己特有的“逻辑相等”概念(不同于对象身份的概念). 2.设计equals() [1]使用instan ...

  3. Java中equals()和hashCode()的关系以及重写equals()和hashCode()的重要性

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6580647.html  一:关系 如果两个对象相等(equal),它们的hashcode一定相同: 如果两个对 ...

  4. java重写equals和hashCode方法

    一.重写equals方法 如果不重写equals,那么比较的将是对象的引用是否指向同一块内存地址,重写之后目的是为了比较两个对象的value值是否相等. 利用equals比较八大包装对象(如int,f ...

  5. 【转】Java中==、equals、hashcode的区别与重写equals以及hashcode方法实例

    原文地址:http://www.cnblogs.com/luankun0214/p/4421770.html 感谢网友的分享,记录下来只为学习. 1.重写equals方法实例   部分代码参考http ...

  6. Java重写equals()和hashCode()

    1.何时需要重写equals() 当一个类有自己特有的 ”逻辑相等”概念(不同于对象身份的概念). 2.设计equals() [1]使用instanceof操作符检查 ”实参是否为正确的类型”. [2 ...

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

    1.重写equals方法实例   部分代码参考http://blog.csdn.net/wangloveall/article/details/7899948 重写equals方法的目的是判断两个对象 ...

  8. Java 重写 equals 与 hashCode 的注意事项

    为什么重写 equals 的时候必须重写 hashCode 大家可能从很多教程中了解到: SUN官方的文档中规定"如果重定义equals方法,就必须重定义hashCode方法,以便用户可以将 ...

  9. Java 重写equals()与hashCode()方法

    List对象的contains方法实际上也是调用的equals()方法来进行逐条对比的. 示例代码: package com.imooc.collection; /** * 课程类 */ public ...

随机推荐

  1. 区分Web前端和后端(转载)

    转载自:http://blog.csdn.net/rosetta/article/details/53871766 前言   做C开发将近六年,基本上没有接触过web相关的东西,原来听别人说web相关 ...

  2. 超轻量级、高性能C日志库--EasyLogger

    [ 声明:版权全部,欢迎转载.请勿用于商业用途. 联系信箱:armink.ztl@gmail.com] EasyLogger 1. 介绍 EasyLogger 是一款超轻量级(ROM<1.6K, ...

  3. hdoj 1455 Sticks 【dfs】

    题意:找最短的木棍可以组成的长度, hdoj  1518 的加强版 代码: #include <stdio.h> #include <string.h> #include &l ...

  4. cloudera impala编译 安装 配置 启动

    无论是采用GDB调试impala或者尝试修改impala源码,前提都是需要本地环境编译impala,这篇文章详细的分享一下impala编译方法以及编译过程遇到的棘手的问题: 前言: impala官方的 ...

  5. ZOJ - 1505 Solitaire 【双向BFS】

    题目链接 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1505 题意 一个8 * 8 的棋盘上面有四个棋子 棋子可以上下左 ...

  6. eclipse新建Maven项目

    1.在eclipse中安装maven插件 2.点击File->new->maven project,出现弹窗后点击next. 接着在弹窗Select an Archetype中,filte ...

  7. ARM NEON 64bit 查找表替换

    没啥效果,如果表的长度在 64个uint8_t之类,应该可以提高查表速度,否则还是C来的快 #ifdef HAVE_NEON_AARCH64 void table_lookup_AArch64_neo ...

  8. 微信小程序消息模板

    wxml: <form bindsubmit='sendSms' report-submit='true' id='fo'> <button form-type='submit'&g ...

  9. Maze迷宫问题(求最优解)

    迷宫地形我们可以通过读文件的形式,通过已知入口逐个遍历坐标寻找通路. 文件如图: 每个坐标的位置用结构体来记录: struct Pos //位置坐标 { int _row; int _col; }; ...

  10. 为UniDBEdit添加拖拽属性

    不知是作者Fashard的疏忽还是有意,UniDBEdit的拖拽属性居然没有发布出来(其他组件都已发布).加上其实也很简单. 打开source目录下的uniDBEdit.pas单元,在TUniDBEd ...