码迷,mamicode.com
首页 > 其他好文 > 详细

自定义类型的对象如何判断相等

时间:2016-04-18 23:54:55      阅读:332      评论:0      收藏:0      [点我收藏+]

标签:

NSObject协议中有两个用于判断等同性的关键方法:

- (BOOL)isEqual:(id)object;  
- (NSUInteger)hash; 

NSObject类对这两个方法的默认实现是:当且仅当其“指针值”(pointer value)完全相等时,这两个对象才相等。如果“isEqual:”方法判定两个对象相等,那么其hash方法也必须返回同一个值。但是,如果两个对象的hash方法返回同一个值,那么“isEqual:”方法未必会认为两者相等。

比如有下面这个类:

@interface EOCPerson : NSObject  
@property (nonatomic, copy) NSString *firstName;  
@property (nonatomic, copy) NSString *lastName;  
@property (nonatomic, assign) NSUInteger age;  
@end 

我们认为,如果两个EOCPerson的所有字段均相等,那么这两个对象就相等。于是“isEqual:”方法可以写成:

- (BOOL)isEqual:(id)object {  
    if (self == object) return YES;  
    if ([self class] != [object class]) return NO;  
 
    EOCPerson *otherPerson = (EOCPerson*)object;  
    if (![_firstName isEqualToString:otherPerson.firstName])  
        return NO;  
    if (![_lastName isEqualToString:otherPerson.lastName])  
        return NO;  
    if (_age != otherPerson.age)  
        return NO;  
    return YES;  
} 

首先,直接判断两个指针是否相等。若相等,则其均指向同一对象,所以受测的对象也必定相等。接下来,比较两对象所属的类。若不属于同一个类,则两对象不相等。EOCPerson对象当然不可能与EOCDog对象相等。不过,有时我们可能认为:一个EOCPerson实例可以与其子类(比如EOCSmithPerson)实例相等。在继承体系(inheritance hierarchy)中判断等同性时,经常遭遇此类问题。所以实现“isEqual:”方法时要考虑到这种情况。最后,检测每个属性是否相等。只要其中有不相等的属性,就判定两对象不等,否则两对象相等。

接下来该实现hash方法了。回想一下,根据等同性约定:若两对象相等,则其哈希码(hash)也相等,但是两个哈希码相同的对象却未必相等。这是能否正确覆写“isEqual:”方法的关键所在。下面这种写法完全可行:

- (NSUInteger)hash {  
    return 1337;  
} 

不过若是这么写的话,在collection中使用这种对象将产生性能问题,因为collection在检索哈希表(hash table)时,会用对象的哈希码做索引。假如某个collection是用set实现的,那么set可能会根据哈希码把对象分装到不同的数组中。在向set中添加新对象时,要根据其哈希码找到与之相关的那个数组,依次检查其中各个元素,看数组中已有的对象是否和将要添加的新对象相等。如果相等,那就说明要添加的对象已经在set里面了。由此可知,如果令每个对象都返回相同的哈希码,那么在set中已有1?000?000个对象的情况下,若是继续向其中添加对象,则需将这1?000?000个对象全部扫描一遍。

hash方法也可以这样来实现:

- (NSUInteger)hash {  
    NSString *stringToHash =  
        [NSStringstringWithFormat:@"%@:%@:%i",  
            _firstName, _lastName, _age];  
    return [stringToHash hash];  
} 

这次所用的办法是将NSString对象中的属性都塞入另一个字符串中,然后令hash方法返回该字符串的哈希码。这么做符合约定,因为两个相等的EOCPerson对象总会返回相同的哈希码。但是这样做还需负担创建字符串的开销,所以比返回单一值要慢。把这种对象添加到collection中时,也会产生性能问题,因为要想添加,必须先计算其哈希码。

再来看最后一种计算哈希码的办法:

- (NSUInteger)hash {  
    NSUInteger firstNameHash = [_firstName hash];  
    NSUInteger lastNameHash = [_lastName hash];  
    NSUInteger ageHash = _age;  
    return firstNameHash ^ lastNameHash ^ ageHash;  
} 

这种做法既能保持较高效率,又能使生成的哈希码至少位于一定范围之内,而不会过于频繁地重复。当然,此算法生成的哈希码还是会碰撞(collision),不过至少可以保证哈希码有多种可能的取值。编写hash方法时,应该用当前的对象做做实验,以便在减少碰撞频度与降低运算复杂程度之间取舍。

自定义类型的对象如何判断相等

标签:

原文地址:http://www.cnblogs.com/drbbq/p/5406142.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!