OC中 判断2个对象相等(isEqual和hash)

先创建一个类CHHPerson作为测试类

CHHPerson.h

#import 

@interface CHHPerson : NSObject

@property (nonatomic,copy) NSString *firstName;
@property (nonatomic,copy) NSString *lastName;
@property (nonatomic,assign) int age;

-(id)initWithFirstName:(NSString *)firstName lastName:(NSString *)lastName age:(int)age;

-(BOOL)isEqualToPerson:(CHHPerson *) person;

@end

CHHPerson.m

#import "CHHPerson.h"

@implementation CHHPerson

static kBuildCount = 0;

-(id)initWithFirstName:(NSString *)firstName lastName:(NSString *)lastName age:(int) age
{
    self = [super init];
    if(self) {
        _firstName = [firstName copy];
        _lastName = [lastName copy];
        _age = age;
    }
    return self;
}

-(BOOL)isEqualToPerson:(CHHPerson *)person
{
    if(person == self)
    {
        return true;
    }
    if(![_firstName isEqualToString:person.firstName])
    {
        return false;
    }
    if(![_lastName isEqualToString:person.lastName])
    {
        return false;
    }
    if(_age != person.age)
    {
        return false;
    }
    return true;
}

/// 2个对象判断相等关键还是 isEqual
- (BOOL)isEqual:(id)other
{
    if ([other class] == [self class]) {
       return [self isEqualToPerson:(CHHPerson *) other];
    } else {
        return [super isEqual:other];
    }
}

/// 为hash table 所用 , 其对应的isEqual 用到这个值
- (NSUInteger)hash
{
    return ++kBuildCount;
    //return 1;
}

@end

== 判断为同一个对象(指针地址判断)

测试代码:

        NSObject * objectA = [NSObject new];
        NSObject * objectB = [NSObject new];
        NSObject * objectAA = objectA;
        
        NSLog(@"objectA == objectB : %d",(objectA == objectB));
        NSLog(@"objectA == objectAA : %d",(objectA == objectAA));

输出结果:

2017-03-15 23:04:34.017969 Effective_9[18875:11149290] objectA == objectB : 0
2017-03-15 23:04:34.018281 Effective_9[18875:11149290] objectA == objectAA : 1

isEqual 判断

单个对象之间的对比

isEqual返回true 和 hash值一样

修改CHHPerson.m 中 hash 方法返回1

- (NSUInteger)hash
{
    //return ++kBuildCount;
    return 1;
}

两个对象对比:

        CHHPerson * personA = [[CHHPerson alloc] initWithFirstName:@"A" lastName:@"A" age:13];
        CHHPerson* personB = [[CHHPerson alloc] initWithFirstName:@"A" lastName:@"A" age:13];
        NSLog(@"personA isEqual personB : %d",([personA isEqual:personB]));

输出结果: 2对象相等

2017-03-16 09:25:24.654742 Effective_9[19008:11167812] personA isEqual personB : 1

isEqual返回true 和 hash值不同

修改CHHPerson.m 中 hash 方法返回

- (NSUInteger)hash
{
    return ++kBuildCount;
    //return 1;
}

同上测试输出结果: 2对象相等

2017-03-16 10:52:14.926642 Effective_9[19261:11223212] personA isEqual personB : 1

单个对象中间用isEqual的结果和hash值无关


那hash值什么时候用到呢?--》集合

如果一个被插入集合类的可变对象是依据其 hash 值来决定其在集合中的位置的话,这个对象的 hash 函数所返回的值在该对象存在于集合中时是不允许改变的。所以以下的测试时当时小白时的笑话~~~

集合对比

Set对比

修改CHHPerson.m 中 hash 方法返回不同值

为了查看打印了那个对象,注释掉lastName在isEqualToPerson中的对比,在hash中打印lastName

** set中只存在1个对象**

测试代码:

        CHHPerson * personA = [[CHHPerson alloc] initWithFirstName:@"A" lastName:@"A" age:13];
        NSMutableSet * set = [NSMutableSet new];
        [set addObject:personA];
        CHHPerson * personC = [[CHHPerson alloc] initWithFirstName:@"A" lastName:@"C" age:13];
        NSMutableSet * set2 = [NSMutableSet new];
        [set2 addObject:personC];
        NSLog(@"set isEqual set2 start");
        NSLog(@"set isEqual set2 : %d",([set isEqual:set2]));

输出结果:2个set相等

2017-03-16 11:25:09.377660 Effective_9[19546:11246836] CHHPerson get hash A
2017-03-16 11:25:09.378474 Effective_9[19546:11246836] CHHPerson get hash A
2017-03-16 11:25:09.378509 Effective_9[19546:11246836] CHHPerson get hash C
2017-03-16 11:25:09.378531 Effective_9[19546:11246836] CHHPerson get hash C
2017-03-16 11:25:09.378543 Effective_9[19546:11246836] set isEqual set2 start
2017-03-16 11:25:09.378603 Effective_9[19546:11246836] CHHPerson get hash A
2017-03-16 11:25:09.378619 Effective_9[19546:11246836] CHHPerson get hash A
2017-03-16 11:25:09.378633 Effective_9[19546:11246836] set isEqual set2 : 1

出乎意料:2个person的hash值不同,2个set竟然相等
查看log可以看出,在set对比时,set是调用了对象的hash方法,但是都是调用personA。

** set中再添加1个对象**

测试代码:

CHHPerson * personA = [[CHHPerson alloc] initWithFirstName:@"A" lastName:@"A" age:13];
        CHHPerson* personB = [[CHHPerson alloc] initWithFirstName:@"A" lastName:@"B" age:15];
        NSMutableSet * set = [NSMutableSet new];
        [set addObject:personA];
        [set addObject:personB];
        CHHPerson * personC = [[CHHPerson alloc] initWithFirstName:@"A" lastName:@"C" age:13];
        CHHPerson* personD = [[CHHPerson alloc] initWithFirstName:@"A" lastName:@"D" age:15];
        NSMutableSet * set2 = [NSMutableSet new];
        [set2 addObject:personC];
        [set2 addObject:personD];
        NSLog(@"set isEqual set2 start");
        NSLog(@"set isEqual set2 : %d",([set isEqual:set2]));

输出结果: 2个set终于不相等了

2017-03-16 11:30:42.348644 Effective_9[19602:11250347] CHHPerson get hash A
2017-03-16 11:30:42.348816 Effective_9[19602:11250347] CHHPerson get hash A
2017-03-16 11:30:42.348841 Effective_9[19602:11250347] CHHPerson get hash B
2017-03-16 11:30:42.348867 Effective_9[19602:11250347] CHHPerson get hash C
2017-03-16 11:30:42.348882 Effective_9[19602:11250347] CHHPerson get hash C
2017-03-16 11:30:42.348896 Effective_9[19602:11250347] CHHPerson get hash D
2017-03-16 11:30:42.348934 Effective_9[19602:11250347] set isEqual set2 start
2017-03-16 11:30:42.348978 Effective_9[19602:11250347] CHHPerson get hash B
2017-03-16 11:30:42.348991 Effective_9[19602:11250347] CHHPerson get hash B
2017-03-16 11:30:42.349014 Effective_9[19602:11250347] set isEqual set2 : 0

注意:
虽然2个set不相等了,但在对比时也是只调用了personB的hash方法。

结(个人猜测):当set中只用1个对象时,isEqual对比和对象的hash值无关,当大于1个对象时才用到对象的hash值

hash 方法返回相同值

** set中2个对象**
输出结果:2个set相等

2017-03-16 11:36:43.732768 Effective_9[19618:11253370] CHHPerson get hash A
2017-03-16 11:36:43.734181 Effective_9[19618:11253370] CHHPerson get hash A
2017-03-16 11:36:43.734215 Effective_9[19618:11253370] CHHPerson get hash B
2017-03-16 11:36:43.734496 Effective_9[19618:11253370] CHHPerson get hash C
2017-03-16 11:36:43.734519 Effective_9[19618:11253370] CHHPerson get hash C
2017-03-16 11:36:43.734537 Effective_9[19618:11253370] CHHPerson get hash D
2017-03-16 11:36:43.734557 Effective_9[19618:11253370] set isEqual set2 start
2017-03-16 11:36:43.734597 Effective_9[19618:11253370] CHHPerson get hash A
2017-03-16 11:36:43.734614 Effective_9[19618:11253370] CHHPerson get hash A
2017-03-16 11:36:43.734623 Effective_9[19618:11253370] CHHPerson get hash B
2017-03-16 11:36:43.734631 Effective_9[19618:11253370] CHHPerson get hash B
2017-03-16 11:36:43.734642 Effective_9[19618:11253370] set isEqual set2 : 1

注意:
虽然2个set相等了,但在对比时也是只调用了personA和 personB的hash方法。

set对比结果:

(个人猜测)
当set中对象个数对应1时,set的isEqual对比时,和对象的isEqual返回有关和hash无关(存疑);当set中对象个数大于1时,set的isEqual对比时,和对象的isEqual和hash返回都有关
但set对比时hash的获取存在问题,求大神指导

NSArray 对比

isEqual返回true 和 hash值不同

测试代码:

CHHPerson * personA = [[CHHPerson alloc] initWithFirstName:@"A" lastName:@"A" age:13];
        CHHPerson* personB = [[CHHPerson alloc] initWithFirstName:@"A" lastName:@"B" age:15];
        NSArray *arr = @[personA,personB];
        CHHPerson * personC = [[CHHPerson alloc] initWithFirstName:@"A" lastName:@"C" age:13];
        CHHPerson* personD = [[CHHPerson alloc] initWithFirstName:@"A" lastName:@"D" age:15];
        NSArray *arr2 = @[personC,personD];
        NSLog(@"arr isEqual arr2 start");
        NSLog(@"arr isEqual arr2 : %d",([arr isEqualToArray:arr2]));

输出结果: 2个Array相等

2017-03-16 11:57:09.848158 Effective_9[19713:11268253] arr isEqual arr2 start
2017-03-16 11:57:09.848736 Effective_9[19713:11268253] arr isEqual arr2 : 1

NSArray 对比结果:

和hash无关,但是和数组排列顺序是有关的

小结:

1.hash方法是为那些需要用到 hashtable 的集合服务的(当然你也可以再isEqual中加入hash值的对比)
2.当set中对象个数对应1时,set的isEqual对比时,和对象的isEqual返回有关和hash无关(存疑);当set中对象个数大于1时,set的isEqual对比时,和对象的isEqual和hash返回都有关
3.NSArray对比时,对象的isEqual和排列顺序有关,和hash无关
4.== 只是判断同一个地址

疑惑

set对比时,对象hash获取的顺序问题,和对比方式

你可能感兴趣的:(OC中 判断2个对象相等(isEqual和hash))