Java中如何正确覆写equals和hashCode方法

285 阅读1分钟

1.什么时候需要覆写equals和hashCode方法?

当类具有自己特有的逻辑相等概念,而且超类还没有覆盖equals方法时,简单说就是需要比较两个对象在逻辑上是否相等。

2.覆写equals方法的要求

需要满足以下五个特性:

  • 自反性:x非null,x.equals(x)返回true
  • 对称性:x,y非null,x.equals(y)y.equals(x)比较结果相同
  • 传递性:x,y,z非null,x.equals(y)为true,y.equals(z)为true,则x.equals(z)为true
  • 一致性:对象在equals方法中比较的关键域的值没有变,多次调用结果相同
  • x非null,x.equals(null)返回false

3.覆写equals和hashCode示例

覆写equals方法的同时应该覆写hashCode方法,否则对象用作HashMap和HashSet中时会有问题,两个方法中用到的关键域应该一致。

import java.util.Objects;

public class ScorePoint {
    private String grade;
    private String team;
    private int score;

    // 第一个关键域赋值给result,其余关键域哈希值依次用result = 31 * result + hashcode累加,如果域为null,它的hashCode可以看作是0
    @Override
    public int hashCode() {
        int result = 0;
        if (grade != null) {
            result = grade.hashCode();
        }
        if (team != null) {
            result = 31 * result + team.hashCode();
        }else{
            result = 31 * result;
        }
        result = 31 * result + Integer.hashCode(score);
        return result;
    }

    // 简单实现,质量与上面的方式相当,性能不好,对性能没有过高要求可以使用
    @Override
    public int hashCode(){
        Objects.hash(grade, team, score);
    }

    @Override
    public boolean equals(Object obj) {
        // 1.性能优化,比较操作可能开销较大
        if (this == obj) {
            return true;
        }

        // 2.类型判断,同时如果obj为null,instance of会返回false
        if (!(obj instanceof ScorePoint)) {
            return false;
        }

        // 3.转成正确的类型
        ScorePoint scorePoint = (ScorePoint) obj;

        // 4.比较关键域
        return (grade != null && grade.equals(scorePoint.grade)) &&
                (team != null && team.equals(scorePoint.team)) &&
                score == scorePoint.score;
    }
}

本文主要参考《Effective Java》