什么情况下需要重写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()的常规协定主要有以下几点:
- 在Java应用程序执行期间,在同一对象上多次调用hashCode()方法时,必须返回相同的整数,前提是对象上equals()方法比较中所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致;
- 如果根据equals()方法比较,两个对象是相等的,那么在两个对象中的每个对象上调用hashCode()方法都必须返回相同的整数结果;
- 以下情况是必须的:如果根据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;
}
}
如有错误,请及时指出。谢谢。
转载请注明出处!