重写 hashCode 和 ==
本课属于 Coddy Dart 学习旅程的“面向对象编程”单元。第 71 课,共 110 课。
默认情况下,Dart 中的两个对象只有在内存中是同一个实例时才相等。这意味着,即使两个对象的值完全相同,它们仍会被视为不同的对象:
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。这两者必须始终一起重写:如果两个对象相等,它们的哈希码就必须相同:
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)都能正常工作。
你将把代码分成两个文件:
coordinate.dart:创建一个Coordinate类,用来表示二维空间中的一个点,并包含final int x和final int y字段。重写==运算符和hashCode,这样两个 x 和 y 值相同的坐标就会被视为相等。使用Object.hash()根据这两个字段生成哈希码。main.dart:导入坐标文件,并演示基于值的相等性如何改变对象比较行为:- 创建两个不同的
Coordinate对象,它们的 x 都是5,y 都是10 - 使用
==打印它们是否相等 - 使用
identical()打印它们是否完全相同(是同一个实例) - 创建一个
Set<Coordinate>,并将两个坐标都添加到其中 - 打印集合的长度(由于它们相等,长度应该是 1!)
- 创建第三个坐标,x 为
3,y 为7,并将它添加到集合中 - 打印集合的最终长度
- 创建两个不同的
这个挑战说明了为什么必须始终一起重写 hashCode 和 ==。Set 使用哈希码来组织元素,因此如果没有正确的 hashCode,即使相等的对象也可能被当作重复项存储!
预期输出:
true
false
1
2亲手试试
import 'coordinate.dart';
void main() {
// TODO: 创建两个不同的 Coordinate 对象,两个对象的 x 都是 5,y 都是 10
// TODO: 用 == 输出它们是否相等
// TODO: 用 identical() 输出它们是否是同一个实例
// TODO: 创建一个 Set<Coordinate>,并将这两个坐标都添加进去
// TODO: 输出集合的长度(它们相等,所以应该是 1!)
// TODO: 创建第三个坐标,x 为 3,y 为 7,并将它添加到集合中
// TODO: 输出集合最终的长度
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Dart 在线编译器