Apex の Map ではクラスをキーとして扱うことができますが、その場合は注意が必要です。
この記事ではクラスをキーとして扱う方法について記述しました。
また、クラスを Set の要素として扱う際も同様の考え方が使えます。
実装例
public class KeyGroup {
Date keyDate;
String keyword;
public KeyGroup(Date keyDate, String keyword) {
this.keyDate = keyDate;
this.keyword = keyword;
}
Boolean equals(Object obj){
if(obj instanceof KeyGroup){
KeyGroup kg = (KeyGroup) obj;
return this.keyDate.isSameDay(kg.keyDate) && this.keyword == kg.keyword;
}
return false;
}
Integer hashCode(){
return keyDate.year() + keyDate.month() + keyword.hashCode();
}
}
Map<KeyGroup, Integer> sampleMap = new Map<KeyGroup, Integer>();
KeyGroup kg1 = new KeyGroup(Date.newInstance(2023, 1, 3), 'hoge');
KeyGroup kg2 = new KeyGroup(Date.newInstance(2024, 2, 4), 'fuga');
KeyGroup kg3 = new KeyGroup(Date.newInstance(2023, 1, 3), 'hoge');
sampleMap.put(kg1, 1);
sampleMap.put(kg2, 2);
System.debug(sampleMap.get(kg3)); // 1 が返される
ポイント
キーとして使用したいクラスに、equals メソッドと hashCode メソッドを実装(オーバーライド)します。
equals メソッドは次の条件を満たす必要があります。
x、y、z が null 以外のインスタンスであるとして、
- 反射性: x.equals(x)
- 対称性: x.equals(y) は、y.equals(x) が true を返す場合にのみ true を返す
- 推移性: x.equals(y) が true を返し、かつ y.equals(z) が true を返す場合、x.equals(z) は true を返す
- 整合性: x.equals(y) の複数の呼び出しで常に true を返すか常に false を返す
- null 以外の参照値 x では、x.equals(null) は false を返す
hashCode メソッドは次の条件を満たす必要があります。
- hashCode メソッドが Apex 要求の実行中に同じオブジェクトで複数回呼び出された場合、同じ値を返す必要がある。
- equals メソッドで 2 つのオブジェクトが等価とされた場合、hashCode は同じ値を返す必要がある。
- equals メソッドで 2 つのオブジェクトが等価でないとされた場合、hashCode は異なる値を返す必要はない。
なぜ equals と hashCode がどちらも必要なのか
get 等でMapのキーの中から一致するキーを探す場合、
- hashCode の値を比較
- 上記が一致していれば、equals で一致を判定
という順で処理が行われます。
hashCode (Integer) 同士の比較は equals を実行するよりも処理が軽いので、すべてのキーに対し equals を実行して比較するよりも全体的な処理は速くなるからです。
コメント