The HIRO Says

If you smell what The HIRO is cooking!!!

equals() メソッドの実装 (1)−基本的な規約

equals() メソッドは、java.lang.Object クラスにあるメソッドで、オブジェクト同士が同じか否かを判定するものです。
初めは単純にオブジェクトの field 同士を比較するだけでよいのかと思っていたんですが、Effective Java によると、色々と細かい仕様が決まっているんですね。

実装

簡単な JavaBeans に equals() メソッドを実装した例を紹介します。

/**
 * 栄養成分表を表す JavaBeans
 */
public class NutritionFacts {

// fields(簡略化のため2つにしました)
    /// 内容量
    private int servingSize;
    // 1人前の量
    private int servings;


// constructors
    public NutritionFacts() {
    }


// getter/setter は省略


// equals()
    /*
     * @see java.lang.Object#equals(java.lang.Object)
     */
    // (1)オーバーライドのミスを防ぐため、明示的に @Override をつける。(1.5 以降)
    @Override
    public boolean equals(Object o) {

        // (2)instanceof で、型チェックと not null チェックを行う。
        if (!(o instanceof NutritionFacts)) {
            return false;
        }

        // (3)参照が同一ならば、後続のチェックをせずに true を返す。結果、パフォーマンスを向上できる。
        if (o == this) {
            return true;
        }

        // (4)既に instanceof 後なので、問題なくキャストできる。
        NutritionFacts target = (NutritionFacts) o;

        // (5)各 field の値が同一か否かを判定する。
        return (this.servingSize == target.servingSize &&
                this.servings    == target.servings);
    }
}

仕様

Effective Java に記載されている仕様は、次の5つです。
(1)同一オブジェクトならば、true を返すこと。(reflexivity)
(2)o1.equals(o2) = true ならば、o2.equals(o1) = true であること。(symmetry)
(3)o1.equals(o2) = true かつ o2.equals(o3) = true ならば、o3.equals(o1) = true であること。(transitivity)
(4)値に変化がなければ、常に同一の結果を返すこと。(consistency:一貫性)
(5)引数が null ならば、false を返すこと。(non-nullity)

補足

上記の例では、non-nullity・reflexivity 及び consistency については理解できると思いますが、symmetry と transitivity については分かり難いのではないかと思います。
symmetry と transitivity については、別途後日コード例を記載します。