Java中重写equals()方法时注意点

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。

猜你喜欢

转载自blog.csdn.net/doujinlong1/article/details/80899976