Menu
CoddyTech

Ghi đè hashCode và ==

Thuộc phần Lập trình hướng đối tượng trong hành trình Dart của Coddy. Bài học 71 trên 110.

Theo mặc định, hai đối tượng trong Dart chỉ bằng nhau khi chúng chính là cùng một instance trong bộ nhớ. Điều này có nghĩa là hai đối tượng có giá trị giống hệt nhau vẫn được xem là khác nhau:

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, hai instance khác nhau!
}

Để so sánh các đối tượng dựa trên giá trị, bạn cần ghi đè cả toán tử == và hashCode. Bạn luôn phải ghi đè cả hai cùng nhau: nếu hai đối tượng bằng nhau, chúng phải có cùng mã băm:

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, các giá trị giống nhau!
}

hashCode rất quan trọng với các cấu trúc tập hợp như Set và khóa của Map. Hàm hỗ trợ Object.hash() của Dart kết hợp nhiều giá trị thành một mã băm. Nếu không có hashCode phù hợp, các đối tượng của bạn sẽ không hoạt động chính xác trong các cấu trúc tập hợp dựa trên mã băm, ngay cả khi bạn đã ghi đè ==.

challenge icon

Thử thách

Dễ

Hãy xây dựng một hệ tọa độ để so sánh các điểm dựa trên giá trị thay vì địa chỉ bộ nhớ! Bạn sẽ tạo một lớp Coordinate triển khai chính xác phép so sánh bằng theo giá trị, giúp lớp hoạt động đúng với các phép kiểm tra bằng nhau và các tập hợp dựa trên mã băm như Set.

Bạn sẽ sắp xếp code thành hai tệp:

  • coordinate.dart: Tạo lớp Coordinate biểu thị một điểm trong không gian 2D với các trường final int x và final int y. Ghi đè cả toán tử == lẫn hashCode để hai tọa độ có cùng giá trị x và y được xem là bằng nhau. Dùng Object.hash() để tạo mã băm từ cả hai trường.
  • main.dart: Nhập tệp tọa độ và minh họa cách phép so sánh bằng theo giá trị thay đổi hành vi so sánh đối tượng:
    • Tạo hai đối tượng Coordinate riêng biệt, cả hai có x: 5 và y: 10
    • In ra xem chúng có bằng nhau không bằng cách dùng ==
    • In ra xem chúng có đồng nhất không (cùng một instance) bằng cách dùng identical()
    • Tạo một Set<Coordinate> rồi thêm cả hai tọa độ vào đó
    • In ra độ dài của tập hợp (kết quả sẽ là 1 vì chúng bằng nhau!)
    • Tạo tọa độ thứ ba với x: 3 và y: 7, rồi thêm tọa độ đó vào tập hợp
    • In ra độ dài cuối cùng của tập hợp

Thử thách này cho thấy vì sao phải luôn ghi đè hashCode và == cùng nhau. Set dùng mã băm để sắp xếp các phần tử, vì vậy nếu không có hashCode phù hợp, ngay cả các đối tượng bằng nhau cũng có thể được lưu thành các bản sao trùng lặp!

Đầu ra dự kiến:

true
false
1
2

Tự làm thử

import 'coordinate.dart';

void main() {
  // TODO: Tạo hai đối tượng Coordinate riêng biệt, cả hai đều có x: 5 và y: 10

  // TODO: Dùng == để in ra kết quả kiểm tra chúng có bằng nhau không

  // TODO: Dùng identical() để in ra kết quả kiểm tra chúng có cùng một instance không

  // TODO: Tạo một Set<Coordinate> và thêm cả hai tọa độ vào đó

  // TODO: In ra số phần tử của tập hợp (phải là 1 vì chúng bằng nhau!)

  // TODO: Tạo tọa độ thứ ba với x: 3 và y: 7, rồi thêm vào tập hợp

  // TODO: In ra số phần tử cuối cùng của tập hợp
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch Dart online