hashcode 和 equals

1、当集合添加新的元素时,先调用这个元素的hashCode()方法,定位到它应该存放的物理位置上。如果这个位置上没有元素,就直接存储在这个位置上,不用再进行比较了;如果这个位置上已经存在了元素,就再调用它的equals()方法与新元素进行比较,相同的话就不存储了,不同的话就散列到其他的位置上。

2、java对equals()方法和hashCode()方法是这样规定的:
  如果两个对象相等,则他们的hashCode值一定相等;
  如果两个对象的hashCode相等,他们并不一定相等。

3、何时需要重写hashcode?

首先,equals()和hashCode()两个函数是紧密结合的,必须同时实现,不能单独重写其中的一个。

在下面的情况下需要重写(其他情况下不需要重写):
1)将一个对象A放入到另一个集合对象B中;
2)使用对象A占作为集合对象B的key,支持对对象B查找元对象、是否容纳和删除等操作;

如果涉及的对象类型不使用于集合对象,就没有必要再设计这两个函数;

当一个对象类型作为集合对象的元对象时(1)),这个对象应该拥有自己处理equals(),equals()先要查null和是否是同一类型。查同一类型是为了避免出现ClassCastException这样的异常给丢出来。查 null是为了避免出现NullPointerException这样的异常给丢出来;

如果你的对象里面容纳的数据过多,那么这两个函数 equals()和hashCode()将会变得效率低。如果对象中拥有无法serialized的数据,equals()有可能在操作中出现错误。想象 一个对象x,它的一个整型数据是transient型(不能被serialize成二进制数据流)。然而equals()和hashCode()都有依靠 这个整型数据,那么,这个对象在serialization之前和之后,是否一样?答案是不一样。因为serialization之前的整型数据是有效的 数据,在serialization之后,这个整型数据的值并没有存储下来,再重新由二进制数据流转换成对象后,两者(对象在serialization 之前和之后)的状态已经不同了。


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方法。
[3]将上面计算得到的散列码保存到int变量c,然后执行 result=37*result+c;
[4]返回result。

 

5、设计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方法。

 

6、实例

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;
    private String name;
 
    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);
       result = 37 * result + (name != null ? name.hashCode() : 0);  // 上面也可以这么写
       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;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值