Java中的equals和hashCode
equals()和hashCode()方法是用来在同一类中做比较用的,尤其是在容器里如set存放同一类对象时用来判断放入的对象是否重复。
这里我们首先要明白一个问题: equals()相等的两个对象,hashcode()一定相等,equals()不相等的两个对象,却并不能证明他们的hashcode()不相等。换句话说,equals()方法不相等的两个对象,hashCode()有可能相等。
在这里hashCode就好比字典里每个字的索引,equals()好比比较的是字典里同一个字下的不同词语。就好像在字典里查“自”这个字下的两个词语“自己”、“自发”,如果用equals()判断查询的词语相等那么就是同一个词语,比如equals()比较的两个词语都是“自己”,那么此时hashCode()方法得到的值也肯定相等;如果用equals()方法比较的是“自己”和“自发”这两个词语,那么得到结果是不想等,但是这两个词都属于“自”这个字下的词语所以在查索引时相同,即:hashCode()相同。如果用equals()比较的是“自己”和“他们”这两个词语的话那么得到的结果也是不同的,此时hashCode() 得到也是不同的
反过来:hashcode()不等,一定能推出equals()也不等;hashcode()相等,equals()可能相等,也可能不等。在object类中,hashcode()方法是本地方法,返回的是对象的地址值,而object类中的equals()方法比较的也是两个对象的地址值,如果equals()相等,说明两个对象地址值也相等,当然hashcode() 也就相等了.
官方注释解释:
在 Java 应用程序执行期间,在同一对象上多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是对象上 equals 比较中所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
如果根据 equals(Object) 方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。
以下情况不 是必需的:如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么在两个对象中的任一对象上调用 hashCode 方法必定会生成不同的整数结果。但是,程序员应该知道,为不相等的对象生成不同整数结果可以提高哈希表的性能。
实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。)
当equals方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。
实际中这在项目中经常被用到,下面是本人所经历的项目中的一个例子,
@Service
public class HandlerRegistry {
private Map<MapKeyPair<TradeTypeEnum, HandlerTypeEnum>, VoucherHandler> config = new HashMap<MapKeyPair<TradeTypeEnum, HandlerTypeEnum>, VoucherHandler>(6);
public void addHandler(TradeTypeEnum tradeType, HandlerTypeEnum handlerType,VoucherHandler handler) {
MapKeyPair<TradeTypeEnum, HandlerTypeEnum> key = new MapKeyPair<TradeTypeEnum, HandlerTypeEnum>(tradeType, handlerType);
config.put(key, handler);
}
public VoucherHandler getHandler(TradeTypeEnum tradeType, HandlerTypeEnum handlerType) {
MapKeyPair<TradeTypeEnum, HandlerTypeEnum> key = new MapKeyPair<TradeTypeEnum, HandlerTypeEnum>(tradeType, handlerType);
return config.get(key);
}
}
class MapKeyPair<V, K> {
private V tradeType;
private K handlerType;
public MapKeyPair(V tradeType, K handlerType) {
this.tradeType = tradeType;
this.handlerType = handlerType;
}
public V getTradeType() {
return tradeType;
}
public void setTradeType(V tradeType) {
this.tradeType = tradeType;
}
public K getHandlerType() {
return handlerType;
}
public void setHandlerType(K handlerType) {
this.handlerType = handlerType;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((handlerType == null) ? 0 : handlerType.hashCode());
result = prime * result + ((tradeType == null) ? 0 : tradeType.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
MapKeyPair<?, ?> other = (MapKeyPair<?, ?>) obj;
if (handlerType == null) {
if (other.handlerType != null)
return false;
} else if (!handlerType.equals(other.handlerType))
return false;
if (tradeType == null) {
if (other.tradeType != null)
return false;
} else if (!tradeType.equals(other.tradeType))
return false;
return true;
}
}
在这段程序中因为MapKeyPair<K,V> 需要作为map的key,所以在class内 我们重写了MapKeyPair的hashcode 和 equals 方法,把MapKeyPair类内的两个成员变量 tradeType 和 handlerType 作为判断equals和hashcode相等的依据。