Menu
Coddy logo textTech

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は、SetMapのキーのようなコレクションにとって非常に重要です。DartのObject.hash()ヘルパーは、複数の値を単一のハッシュコードに結合します。適切なhashCodeがないと、たとえ==がオーバーライドされていても、オブジェクトはハッシュベースのコレクションで正しく動作しません。

challenge icon

チャレンジ

簡単

メモリ番地ではなく、値によってポイントを比較できる座標システムを構築しましょう!値ベースの等価性を適切に実装した Coordinate クラスを作成し、等価性チェックや Set のようなハッシュベースのコレクションで正しく動作するようにします。

コードを2つのファイルに分けて構成します:

  • coordinate.dart: final int xfinal 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つ目の座標を作成し、セットに追加します。
    • セットの最終的な長さを出力します。

このチャレンジは、なぜ 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() を使用します。hashCodeSetMap のようなコレクションにとって非常に重要です。これがないと、等しいオブジェクトがハッシュベースのコレクションで正しく機能しません。

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: セットの最終的な長さを出力します
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン