首页 > 代码库 > 第8条:理解“对象等同性”这一概念
第8条:理解“对象等同性”这一概念
1、== 操作符
比较的是两个指针本身,而不是其所指的对象。
2、NSObject协议中的isEqual:方法
一般来说两个类型不同的对象总是不相等的。如果已经知道两个对象都属于同一个类,那么就可以使用该方法了。
例:
- (BOOL)isEqual:(id)object {
if (self == object) return YES; //判断两个指针是否相等。若相等,则指向同一对象。
if ([self class] != [object class]) return NO; //如果不是同一类,那必然不相等。
Person *otherPerson = (Person*)object; //有时我们可以认为一个类对象可以和子类对象相等。所以在继承体系中,检测每个属性是否相等来判断
if (![_firstName isEqualToString:otherPerson.firstName]) return NO;
if (![_lastName isEqualToString:otherPerson.lastName]) return NO;
if (_age != otherPerson.age) return NO;
return YES;
}
3、NSObject协议中的hash方法
在编写hash方法时,应该用当前的对象做做实验,以便减少碰撞频度与降低运算复杂度之间取舍。
在collection中,会用对象的哈希码做索引。建立哈希表。通过查找哈希表中的索引来查找元素。这样对性能消耗大。
hash值可以自定义。
例1:-(NSUInteger)hash { return 1337; }
例2:-(NSUInteger)hash {
NSString *stringToHash = [NSString stringWithFormat:@"%@:%@:%i", _firstName, _lastName, _age];
return [stringToHash hash]; //通过返回的字符串来计算hash值。 这种方法负担创建字符串的开销,比例1中返回单一值要慢。 如果添加到collection中也会产生性能问题。因为要想添加到collection中,必须先计算其哈希码。
}
例3:-(NSUInteger)hash {
NSUInteger firstNameHash = [_firstName hash];
NSUInteger lastNameHash = [_lastName hash];
NSUInteger ageHash = [_age hash];
return firstNameHash ^ lastNameHash ^ ageHash; //这种做法既能保持较高效率,又能使生成的哈希码至少位于一定范围之内,而不会过于频繁地重复。当然,这种算法生成的哈希码还是会碰撞,不过至少可以保证哈希码有多种可能的取值。
}
4、NSString方法中有一个特有的方法:isEqualToString:
该方法传递的对象必须是NSString,否则结果未定义。
这个方法比第2种方式快,第二种方法不知道对象的类型。
5、NSArray 与 NSDictionary类中也具有特殊的方法
isEqualToArray isEqualToDictionary
数组的检测方式:先比较两个数组的对象个数是否相等,再比较对应位置的两个对象调用其isEqual方法。 这叫做“深度等同性判定”。所以有时只需比较部分数据就可以判定二者是否等同。这是提高Hash算法的一种方式。例如:唯一标识符,在数据库中用作“主键”。
6、自定义判定方法 (两个方法同时实现)
如果受测对象与接收消息的对象都属于同一个类,那么就调用自己编写的判定方法,否则就交由超类来判断。
-(BOOL)isEqualToPerson:(Person*)otherPerson {
if (self == object) return YES;
if (![_firstName isEqualToString:otherPerson.firstName]) return NO;
if (![_lastName isEqualToString:otherPerson.lastName]) return NO;
if (_age != otherPerson.age) return NO;
return YES;
}
- (BOOL)isEqual:(id)object {
if ([self class] = [object class]) return [self isEqualToPerson:(Person*)object];
else return [super isEqual:object];
}
注意:
第2、3种方式:如果isEqual方法判定两个对象相等,那么其hash方法必须返回同一个值;但是如果hash方法返回同一个值,isEqual方法未必会认为两者相等。也就是说两对象相等,hash值一定相等;但hash值相等,两对象未必相等。
第4、5方式:由于OC在编译期不做强类型检查,所以容易传入类型错误的对象。开发者应该保证所传对象的类型正确。
优点是:更容易读懂,而且不用检查两个受测对象的类型了。
容器中可变类的等同性:
例:NSMutableSet 中,添加数据后,再改变数据,数据的哈希码变化的参照不同。所以结果难预料。
第8条:理解“对象等同性”这一概念