2

我有一个简单的对象列表。我想为每个对象计算一种哈希值,用于对列表进行排序。

我的问题是:谁负责计算哈希?

1/ 名单

因为哈希方法是特定于列表的,并且应用于每个对象。对象只是对象,它们不知道排序和散列。

2/ 每个对象

因为该对象是最佳候选对象,因为他拥有所有数据来执行此操作。这可以根据其他人无法访问的内部数据来计算。

3/ 另一个挑战者?就像列表和对象之间的控制器?

4

2 回答 2

4

定义使用的等价概念的类。

如果一个对象定义了一个通用的相等概念,那么它应该定义一个与之对应的哈希码,作为该工作的一部分。

毕竟,正是那个类“知道”如何定义Equals(), isEqual(),areEqual==其他任何东西。有必要 when a == bthat hash(a) == hash(b),所以它是唯一可以这样做的类。

但是,如果另一个类定义了一个相等的概念,(可能以不同的方式使用不同的概念,其中人们可能认为字符串相等或不相等的不同方式是一个经典示例),那么该类必须出于类似的原因定义哈希码。

作为示例,.NET 表达了这种责任联系。在 .NET 中,所有对象都有一个Equals(). 这是否是一件好事是有争议的(有些人更喜欢 C++ 方法,其中一个对象不需要有任何与另一个相等的感觉),但一旦完成,所有对象也有一个GetHashCode(),因为之间的联系一个和另一个。.NET 也有IEqualityComparer<T>并且IEqualityComparer它定义了一个类对特定的非内置平等感负责的方法。在这里,要对一个人负责,就需要对另一个人负责。

现在。哪个更好?

好吧,如果在给定的情况下对“等于”的含义有一种非常明显的感觉,那么它可能应该由类来处理:相同坐标或相同复数或引用相同实数的两个表示- world 对象,在大多数情况下应该被认为是相等的。所以这给出了默认使用。

如果在给定容器类型的上下文中,对于 equals 的含义有非常明显的意义,那么应该在此处应用。

否则应该有一个定义它的连接器。因此,我们可以很好地分离关注点。

但是,我们可以将这三者巧妙地结合在一起。我们定义了一个默认连接器。它的实现只是传递调用以获取哈希码或测试与对象上定义的相等性。

我们定义任何通用哈希表、哈希集等以始终使用连接器,并在构造时使用默认值或默认模板参数(如果语言具有允许这样做的通用/模板方法,例如 C++会,而 C# 例如不会),因此默认情况下我们使用此默认连接器。

在定义依赖于特定概念视图来实现其目的的特殊用途集合类型时,我们从这些集合之一构建它,覆盖连接器。

这条规则的另一面是,如果您没有为所有可相等的对象提供哈希码的定义方法(例如,您有一个==覆盖机制,但没有对 a 的深度支持GetHashCode()),那么您必须使用连接器方法。请注意,虽然 C++ 例如确实有==,但它没有那种知道如何拥有给定对象的支持。因此,STL 必须有一个hash_map并且对其开箱即用的默认设置只有非常有限的支持。

于 2012-09-04T15:07:50.290 回答
1

您的对象应包含计算哈希码值的方法。

在 java 中,Object 是所有类的父类,它具有 hashCode() 方法(Java Object)。这意味着Java中的每个对象都有这个方法来计算这个方法。背后的原因纯粹是对信息的封装。hashCode() 是在类属性上执行的,因此它应该放在那个特定的类中。

于 2012-09-04T17:04:37.483 回答