hashCode と == のオーバーライド
CoddyのDartジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 71/110。
デフォルトでは、Dartにおける2つのオブジェクトは、メモリ上の全く同じインスタンスである場合にのみ等しいとみなされます。つまり、同一の値を持つ2つのオブジェクトであっても、依然として別物とみなされることを意味します。
class Point {
int x, y;
Point(this.x, this.y);
}
void main() {
var p1 = Point(3, 4);
var p2 = Point(3, 4);
print(p1 == p2); // false - 異なるインスタンスです!
}オブジェクトをその値で比較するには、== 演算子と hashCode の両方をオーバーライドする必要があります。これら2つは常に一緒にオーバーライドしなければなりません。2つのオブジェクトが等しい場合、それらは同じハッシュコードを持たなければなりません:
class Point {
final int x, y;
Point(this.x, this.y);
@override
bool operator ==(Object other) {
if (other is! Point) return false;
return x == other.x && y == other.y;
}
@override
int get hashCode => Object.hash(x, y);
}
void main() {
var p1 = Point(3, 4);
var p2 = Point(3, 4);
print(p1 == p2); // true - 同じ値です!
}hashCodeは、SetやMapのキーのようなコレクションにとって非常に重要です。DartのObject.hash()ヘルパーは、複数の値を単一のハッシュコードに結合します。適切なhashCodeがないと、たとえ==がオーバーライドされていても、オブジェクトはハッシュベースのコレクションで正しく動作しません。
チャレンジ
簡単メモリ番地ではなく、値によってポイントを比較できる座標システムを構築しましょう!値ベースの等価性を適切に実装した Coordinate クラスを作成し、等価性チェックや Set のようなハッシュベースのコレクションで正しく動作するようにします。
コードを2つのファイルに分けて構成します:
coordinate.dart:final int xとfinal int yフィールドを持つ、2次元空間の点を表すCoordinateクラスを作成します。同じ x と y の値を持つ2つの座標が等しいと見なされるように、==演算子とhashCodeの両方をオーバーライドしてください。両方のフィールドからハッシュコードを生成するには、Object.hash()を使用します。main.dart: 座標ファイルをインポートし、値ベースの等価性がオブジェクトの比較動作をどのように変えるかを実演します:- x:
5、y:10を持つ2つの別々のCoordinateオブジェクトを作成します。 ==を使用して、それらが等しいかどうかを出力します。identical()を使用して、それらが同一(同じインスタンス)かどうかを出力します。Set<Coordinate>を作成し、両方の座標をそれに追加します。- セットの長さを出力します(等しいため、1になるはずです!)。
- x:
3、y:7を持つ3つ目の座標を作成し、セットに追加します。 - セットの最終的な長さを出力します。
- x:
このチャレンジは、なぜ hashCode と == を常に一緒にオーバーライドしなければならないのかを示しています。Set は要素を整理するためにハッシュコードを使用するため、適切な hashCode がないと、等しいオブジェクトであっても重複して保存される可能性があります!
期待される出力:
true
false
1
2チートシート
デフォルトでは、Dartの2つのオブジェクトは、メモリ内の同じインスタンスである場合にのみ等しいとみなされ、値が同じであっても等しいとはみなされません。
var p1 = Point(3, 4);
var p2 = Point(3, 4);
print(p1 == p2); // false - different instances!オブジェクトを値で比較するには、== 演算子と hashCode の両方をオーバーライドします。これらは常にセットでオーバーライドする必要があります。
class Point {
final int x, y;
Point(this.x, this.y);
@override
bool operator ==(Object other) {
if (other is! Point) return false;
return x == other.x && y == other.y;
}
@override
int get hashCode => Object.hash(x, y);
}複数の値を1つのハッシュコードに結合するには、Object.hash() を使用します。hashCode は Set や Map のようなコレクションにとって非常に重要です。これがないと、等しいオブジェクトがハッシュベースのコレクションで正しく機能しません。
2つのオブジェクトが(単に値が等しいだけでなく)同じインスタンスであるかどうかを確認するには、identical() を使用します。
print(identical(p1, p2)); // false - different instances自分で試してみよう
import 'coordinate.dart';
void main() {
// TODO: x: 5、y: 10 を持つ2つの別々の Coordinate オブジェクトを作成します
// TODO: == を使用して、それらが等しいかどうかを出力します
// TODO: identical() を使用して、それらが同一(同じインスタンス)かどうかを出力します
// TODO: Set<Coordinate> を作成し、両方の座標をそこに追加します
// TODO: セットの長さを出力します(等価なので 1 になるはずです!)
// TODO: x: 3、y: 7 を持つ3つ目の座標を作成し、セットに追加します
// TODO: セットの最終的な長さを出力します
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
4Null Safety
Null Safety 入門Nullable と Non-Nullable? 演算子と ! 演算子late キーワードと Null SafetyNull-Aware 演算子クラスにおける Null Safetyまとめ:ユーザープロフィールシステム10コレクションとジェネリクス
List, Set, Map の概要型安全なコレクションジェネリッククラスジェネリックメソッドジェネリクスの制約Iterable と Iteratorまとめ:ジェネリックなストレージ11特殊メソッド
toString() のオーバーライドhashCode と == のオーバーライドComparable インターフェースcall() メソッドnoSuchMethod のオーバーライドまとめ:カスタムコレクション