zoukankan      html  css  js  c++  java
  • iOS 一个对象的等同性

    1、认识NSString中==、- (BOOL)isEqual:(id)object;,- (NSInteger)hash;, - (BOOL)isEqualToString:(NSString *)otherString;一个运算符和三个函数。

    1、== 是比较两个指针本身是否相同,而不是指针所指的对象。

    2、NSObject协议中isEqual:, hash方法的默认实现都是当且仅当“指针值”完全相等时,这两个对象才相等。

    对象的“等同性”:如果两个对象比较,isEqual:方法返回YES,两个对象的hash值必定相等,但是二者的hash值相等,isEqual:函数的返回值不一定是YES,也即两个hash值相同的对象未必相等
    自定义类的实现

    @interface Person: NSObject
    @property (nonatomic, copy) NSString *firstName;
    @property (nonatomic, copy) NSString *lastName;
    @property (nonatomic, assign) NSUInteger age;
    @end
    
    @implementation
    /*
          直接判断两个指针是否是同一个,一样的话,肯定所指的对象必是同一个。
          否则,比较两个对象所属的类,若不是同一个类,则二者必不相等。其实,不严格来讲,如果一个父类和一个子类的实例比较可以相等,另当别论,因为在继承体系中确实会遇到此问题。
          接下来,比较各个属性值是否相等。
    */
    - (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;
    }
    
    
    /*可行但是不好的一种方法:
         这种写法会有性能问题,试想,一个集合类collection(NSArray或者NSSet,NSDictionary)中有多个该类型的对象,collection在检索哈希表(hash table)时,会用对象的哈希码作为索引。假如某个collection是用set实现的,那么set可能会根据哈希吗把对象分装到不同的数组中。 在向set中添加新对象时,要根据其hash码找到与之相关联的数组,一次检查其中各个元素,看数组中已有的对象是否和将要添加的新对象相等。如果相等,那么就说明要添加的对象已经在set里了。由此可见,如果每个对象都返回相同的hash码,那么在set中已有1000000个对象的情况下,若是继续向其中添加对象,则需要将这1000000个对象全部扫描一遍。
    */
    - (NSUinteger)hash {
          return 1337;
    }
    
    /*
          另一种实现
          将Person对象中的属性都塞入一个字符串中,然后用hash方法返回该字符串的哈希码。这样就符合“等同性”约定。因为两个相等的Person总会返回相等的哈希码。但是这种方法要创建字符串,拼接并生产hash码,开销显然比第一种直接返回一个单一数值大。把这种哈希实现的对象添加到collection时也会产生性能问题,因为要添加必须先计算一遍hash。
    */
    - (NSUinteger)hash {
          NSString *stringToHash = [NSSting stringWithFormat:@"%@:%@:%i",_firstName, lastName, _age];
          return [stringToHash hash];
    }
    
    /*
          最适合的一种实现
           这种做法既能保持一定的高效率,又能时生成的hash至少位于一定范围之内,而不会过于频繁地重复。
    */
    - (NSUinteger)hash {
          NSUinteger firstNameHash = [_firstName hash];
          NSUinteger lastNameHash = [_lastName hash];
          NSUinteger ageHash = _age;
    
          return firstNameHash = firstNameHash^lastNameHash^ageHash;
    }
    
    
    /*
          在自定义的方法中,要实现isEqualToPerson 和 isEqual:方法
    */
    - (BOOL)isEqualToPerson:(Person *)otherPerson {
          if(self == otherPerson) 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];
          }
    }
    
    @end
    

    hash碰撞时不可能避免的,我们编写该方法时要注意减少碰撞和降低计算hash的复杂度。

    如果一个Person 对象是根据数据库里的数据创建的,那么数据库中肯定有主键,由于主键是唯一标识符,我们这时就可以根据该唯一标识符来判断等同性

    collection 容器中最好不要放入可变类型的对象

  • 相关阅读:
    vector<vector<int>> 判断三个数为一组是否重复
    数位dp——hdu2089不要62
    nyoj1099 四点坐标判断正方形
    构造回文——最长公共子序列问题 java
    nyoj08 一种排序
    记录一个protobuf枚举类型引发问题的分析和思考
    记录一下996.icu
    Android N requires the IDE to be running with Java 1.8 or later
    使用fresco后引发的关于造轮子的思考
    使用了一段时间的instant run 记录一下遇到的问题
  • 原文地址:https://www.cnblogs.com/wjw-blog/p/13188278.html
Copyright © 2011-2022 走看看