社内se × プログラマ × ビッグデータ

プログラミングなどITに興味があります。

Java 自作クラスを Map のキーにする

Map のキーは、int 型 や String 型で済ませることが多い。
自作クラスを Map のキーにする機会はたぶん今までなかった。
今回たまたま、それをする機会があったのだけど、get する時に果たして Map に格納されているものと等しいキーとして認識してくれるのだろうか?

作成したクラス

オブジェクトのソート条件を保持するクラス。
ソート対象フィールド名と、昇順・降順の何れかを保持する。

public final class SortCondition {
	    private final String field;
	    private final Direction direction;
	    
	    public SortCondition(String field, Direction direction) {
	    	this.field = field;
	    	this.direction = direction;
	    }
}
Map の生成

こんな感じで Map を生成する。

Map<SortCondition, Comparator<Item>> comparatorMap = new HashMap<>();
comparatorMap.put(new SortCondition("reviewAve", Direction.ASC), Comparator.comparing(Item::getReviewAve));
Map から get してみる
SortCondition condition1 = new SortCondition("reviewAve", Direction.ASC);
Comparator<Item> comparator = this.comparatorMap.get(condition1);
System.out.println(comparator);  // <- null

見た目上は、同じキーを生成しているつもりでも、インスタンスが異なるので、値は取得できず comparator は null。

Map に入っているものと一致するキーにするためには?

SortCondition 内で hashCode() と equals() を正しくオーバーライドする必要があります。
SortCondiiton クラスに以下を追記します。

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof SortCondition) {
            SortCondition condition = (SortCondition) obj;
            return this.field.equals(condition.field) && this.direction.equals(condition.direction);
        } else {
            return false;
        }
    }

    @Override
    public int hashCode() {
        return Objects.hash(field, direction);
    }

equals() の結果が true で、hashCode() の結果が両オブジェクトで等しくなるので、この状態であれば一致するキーがあった時、Mapから対応する値が取得されるようになります。

SortCondition condition1 = new SortCondition("reviewAve", Direction.ASC);
Comparator<Item> comparator = this.comparatorMap.get(condition1);
System.out.println(comparator);  // <- 指定したキーで、値(null ではない) が取得できた
所感

必要になるケースは少ないと思いますが、やや複雑な条件における Key に基づく Value を管理したい場合、自作クラスをキーとして扱うことがあるかもしれません。
equals() についてはイメージがつきやすいですが、hashCode() についてもケアしないといけません。
オーバーライドしないと、Object の hashCode がそのまま使われるので、Mapに入っているキーと実際に使おうとしているキーのインスタンスが異なることから、返却されるハッシュ値も異なります。