首页 > 代码库 > 第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、NSArrayNSDictionary类中也具有特殊的方法

   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条:理解“对象等同性”这一概念