Java中重写equals()方法时注意点
一直说,重写一个对象的equals()方法时我们必须重写HashCode()方法,但是如果我们不重写呢?会有什么影响呢?
首先看一下,什么情况下我们需要重写equals()方法?
一个新定义的对象,如果需要比较时,这时候我们需要重写一下equals()方法,否则,用jdk自定义的equals()的话,会造成只要不是一个内存地址就不返回相等。
先定义一个类:
public class HeroStat {
private final int strength;
private final int intelligence;
private final int luck;
// All constructors must be private.
private HeroStat(int strength, int intelligence, int luck) {
this.strength = strength;
this.intelligence = intelligence;
this.luck = luck;
}
// Static factory method to create new instances.
public static HeroStat valueOf(int strength, int intelligence, int luck) {
return new HeroStat(strength, intelligence, luck);
}
public int getStrength() {
return strength;
}
public int getIntelligence() {
return intelligence;
}
public int getLuck() {
return luck;
}
}
看下比较的代码:
public static void main(String[] args) {
HeroStat statA = HeroStat.valueOf(10, 5, 0);
HeroStat statB = HeroStat.valueOf(10, 5, 0);
HeroStat statC = HeroStat.valueOf(5, 1, 8);
LOGGER.info(statA.toString());
LOGGER.info("Is statA and statB equal : {}", statA.equals(statB));
LOGGER.info("Is statA and statC equal : {}", statA.equals(statC));
}
这里如果我们没有重写equals方法,则输出A.equals(B)肯定返回false,因为比较的是==,如果重写了,则可以返回为true。
那么,如果我们只重写equals()方法呢?
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
HeroStat other = (HeroStat) obj;
if (intelligence != other.intelligence) {
return false;
}
if (luck != other.luck) {
return false;
}
if (strength != other.strength) {
return false;
}
return true;
}
像这样,则可以满足我们的需求,比较这个对象的属性,并且满足java规定的equals()方法的5个特性:
1,对称性,A.equals(B)==true B.equals(A)也一定为true
2,反射性 A.equals(A) 一定为true
3,类推性 A.equals(B)==true B.equals(C)==true,则A.equals(C)==true
4,一致性 A.equals(B)==true时,不管调用多少次都应该为true,不会改变
5,非空性 A.equals(null)一定为false。
这样看起来一点问题都没有了,虽然我们没有重写hashCode()方法,但是已经ok了。
但是,真的是这样吗?
我们试着使用HashSet和HashMap这2个类。
看代码:
public static void main(String[] args) {
HeroStat statA = HeroStat.valueOf(10, 5, 0);
HeroStat statB = HeroStat.valueOf(10, 5, 0);
HeroStat statC = HeroStat.valueOf(5, 1, 8);
Set<HeroStat> set = new HashSet<>();
set.add(statA);
set.add(statB);
set.add(statC);
System.out.println(set);
}
console 输出:
[HeroStat [strength=10, intelligence=5, luck=0], HeroStat [strength=10, intelligence=5, luck=0], HeroStat [strength=5, intelligence=1, luck=8]]
我们发现,set中把3个对象全部插入进去了,但是statA和statB其实是equals返回为true的。
这里就暴露出问题了,如果不重写hashCode()方法,则有关hashCode的地方都会有问题,比如HashSet,HashMap。
那么如果要重写hashCode()方法时,我们要注意什么呢?
A.equals(B) 则必须使得 A.hashCode() == B.hashCode();
如果 A.hashCode() != B.hashCode() 则 A.equals(B) 一定为false。