2009-01-14 43 views
10

-hash的文档说明,当可变对象存储在集合中时,它不能更改,并且类似地-isEqual:的文档说明-hash值必须与相同对象的值相同。用于在可变可可对象上实现-hash的技巧

鉴于此,是否有人对实施-hash的最佳方式有任何建议,以使其符合这两个条件,但是实际上是智能计算的(即不仅仅返回0)?有谁知道框架提供的类的可变版本是如何做到的?

最简单的事情当然就是忘记第一个条件(关于它不会改变),并且确保我在事件集合中不会意外地改变对象,但是我想知道是否有任何解决方案更多灵活。

编辑:我不知道这里是否有可能维持2个合同(其中相等的对象具有相同的哈希值,并且当对象是一个集合的哈希值不改变)当我变异内部对象的状态。我的意思是说“不”,除非我做了一些愚蠢的事情,比如总是为散列返回0,但这就是为什么我要问这个问题。

+0

猜测这是一个老问题,刚刚发现它......但不是可变对象用作通常复制的集合中的键吗?这不就是为了避开这个问题吗? – nielsbot 2012-03-16 03:24:09

+0

@nielsbot:只复制NSDictionaries的密钥。 NSSet不复制它的对象,`CFDictionarySetValue()`API也不复制它的键。 – 2012-03-16 04:29:28

+0

`CFDictionarySetValue`确实会将`kCFTypeDictionaryKeyCallbacks`传递给`CFDictionaryCreate`,否?文档几乎是非感性的......我想一个可变集合obj可以,呃,缓存散列值,这与假设一个集合中的可变obj不会改变它的散列相同,对吧? – nielsbot 2012-03-16 08:36:46

回答

2

有趣的问题,但我想你想要的是逻辑上是不可能。假设你从2个对象A和B开始。它们都不同,它们以不同的哈希码开始。你将两个都添加到一个哈希表。现在,你想改变A,但你不能改变哈希码,因为它已经在表中了。但是,可以用这样的方式来改变A,即.equals()B.

在这种情况下,你有两个选择,而且作品:

  1. 变迁的哈希码等于B.hashcode,违反不改变的哈希码,而在哈希表的约束。
  2. 不要更改散列码,在这种情况下,A.equals(B)但它们不具有相同的散列码。

在我看来,没有可能的方式做到这一点,而不使用常量作为散列码。

-2

在Java中,大多数可变类完全不会覆盖Object.hashCode(),因此默认实现将返回基于对象地址且不会更改的值。它可能只是同与目标C.

2

我的文档阅读是一个可变对象为hash可以(也许应该)变化值,当它发生突变,但不应该变化,当对象没有发生变异。因此,要引用的文档部分是这样说的:“不要改变存储在集合中的对象,因为这会导致其值更改。”

要直接从NSObject documentation for hash引证:

如果可变对象被添加到使用散列值来 确定对象的所述 集合中的位置,由 散列方法返回的值的 集合的对象不能在 集合中更改,而对象位于 集合中。 因此,无论是散 方法不能依赖于任何的 对象的内部状态信息或 您必须确保对象的 内部状态信息不 变化,而对象是 集合英寸

(重点煤矿。)

0

既然你已经重写-isEqual:做一个基于价值的比较,你确定你真的需要打扰-hash吗?

我无法猜到你当然需要什么,但是如果你想在不偏离预期的-isEqual实现的情况下进行基于价值的比较:只有当哈希值相同时才返回YES,更好的方法可能是模仿NSString的-isEqualToString :,所以要创建你自己的-isEqualToFoo:方法,而不是使用或覆盖-isEqual :.

1

这里的问题并不是如何满足这两个要求,而是你应该在哪一个见面。在Apple的文档中,明确指出:

可变字典可以放在哈希表中,但不能在哈希表中进行更改。

这就是说,看起来更重要的是你满足哈希的平等要求。对象的散列应始终是检查对象是否与另一个对象相同的一种方法。如果情况并非如此,那么它不是一个真正的散列函数。

为了完成我的回答,我将举一个好的散列实现的例子。假设您正在为您创建的集合编写-hash的实现。该集合将一组NSObject作为指针存储。由于所有NSObjects实现哈希函数,你可以用自己的哈希值计算集合的哈希值:

- (NSUInteger)hash { 
    NSUInteger theHash = 0; 
    for (NSObject * aPtr in self) { // fast enumeration 
     theHash ^= [aPtr hash]; 
    } 
    return theHash; 
} 

这样,含有相同的指针(以相同的顺序)两个收集对象将具有相同的哈希值。