JAVA类中的equals()方法和hashCode()方法的重写

什么情况下需要重写equals()方法?

在比较两个两个对象时,可以使用==和equals()。前者可以理解为潜比较,既比较对象的引用地址是否相等。后者属于深比较,比较的是两个对象的引用所指向的内容是否相等。

在Object类中已经定义了equals()方法,但该方法是直接采用==操作符实现的,因此子类如果不重写此方法,那么该方法的比较结果和==是一样的。为了方便的比较两个对象的内容是否相等,在定义类的时候一般建议重写此方法。

如何重写equals()方法?

在重写一个类的equals方法之前,要理解两个对象在什么情况下才完全>相等。
重写equals()方法的实例代码如下:

public class Person {
    private String id;
    private String name;

    public String getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    //覆盖equals方法
    public boolean equals(Object o) {
        if(o == null) {
            return false;
        }
        if(this == o) {
            return true;
        }
        if(this.getClass() != o.getClass()) {
            return false;
        }
        Person p = (Person)o;
        return id.equals(p.getId()) && name.equals(p.getName());
    }
}
什么情况下需要重写hashCode()方法?

重写了类的equals()方法主要是为了比较两个对象的内容是否相等。hashCode()方法主要返回调用该方法的对象的整数形式的散列码值。

如果一个类重写了equals()方法,通常也有必要重写hashCode()方法。目的是为了维护hashCode()方法的常规协定,该协定声明相等对象必须具有相等的散列码。

hashCode()的常规协定主要有以下几点:

  1. 在Java应用程序执行期间,在同一对象上多次调用hashCode()方法时,必须返回相同的整数,前提是对象上equals()方法比较中所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致;
  2. 如果根据equals()方法比较,两个对象是相等的,那么在两个对象中的每个对象上调用hashCode()方法都必须返回相同的整数结果;
  3. 以下情况是必须的:如果根据equals()方法比较两个对象不想等,那么在两个对象中的每个对象上调用hashCode()方法必定会生成不同的整数结果。但是,程序员应该知道,为不相等的对象生成不同的整数结果可以提高散列表的性能

实际上,有Object类定义的hashCode()方法确实会针对不同的类返回不同的散列码。(通常是将该对象的内部地址转换成整数来实现的,但是Java编程语言不需要这种实现技巧。)

注意:相等的对象必须有相同的散列码,反之散列码相等则不一定对象相等,而且不想等的对象并不一定需要有不同的散列码。

基于散列法的集合需要使用hashCode()方法返回的散列码值来存储和管理元素,例如HashTable、HashMap、和HashSet等,在使用这些集合时,首先会根据元素对象的散列码值确定其存储位置,然后在根据equals()方法结果判断元素对象是否存在。最后根据判断结果执行不同的处理。

因此,实际应用时,如果重写了equals()方法,那么hashCode()方法也有必要被重写。

如何重写hashCode()方法?

hashCode()方法在重写时,通常按照以下设计原则实现:
1. 把某个非零常数值,例如17,保存在int类型变量result中。
2. 对对象中每一个关键域f(指在equals()方法中考虑的每一个域)参照以下原则处理:
- boolean型,计算(f ? 0 : 1);
- byte、char、和short型,计算(int);
- long型,计算(int)(f^(f>>>32));
- float型,计算Double.doubleToLongBits(double域名称)得到一个long域,再执行long的处理;
- 对象类型,递归调用它的hashCode()方法;
- 数组域,对其中每个元素调用他的hashCode()方法。
3. 将上面计算的到的散列码保存到int型变量c,再执行result=37*result+c。
4. 返回resul。

重写hashCode()方法的实例代码如下:

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;

    //override equals
    public boolean equals(Object o) {
        if(o == null)
            return false;
        if(this.getClass() != o.getClass())
            return false;
        Unit u = (Unit)o;
        return u.ashort == ashort && u.achar == achar && u.abyte == abyte && u.abool == abool && u.along == along && Float.floatToIntBits(u.afloat) == Float.floatToIntBits(afloat) && Double.doubleToLongBits(u.adouble) == Double.doubleToLongBits(adouble) && u.aObject.equals(aObject) && equalsInts(u.ints) && equalsUnits(u.units);
    }

    private boolean equalsInts(int[] aints) {
        return Arrays.equals(ints, aints);
    }

    private boolean equalsUnits(Unit[] aUnits) {
        return Arrays.equals(units, aUnits);
    }

    //override hashCode()
    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 : aints)
            result = 37 * result + i;
        return result;
    }

    private int unitsHashCode(Unit[] aUnits) {
        int result = 17;
        for(Unit u : aUnits)
            result = 37 * result + u.hashCode();
        return result;
    }
}

如有错误,请及时指出。谢谢。
转载请注明出处!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值