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

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

CHHPerson.h

#import <Foundation/Foundation.h>

@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获取的顺序问题,和对比方式

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容

  • 前言 对数据的等同性判断包括对基本数据类型等同性的判断和对象等同性的判断。对基本数据类型等同性的判断是非常简单的,...
    VV木公子阅读 1,444评论 0 8
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,567评论 18 399
  • isEqual 比较对象是否相等,在OC中目前有两种方式:== 和 isEqual:方法。对于==方法,对于指针类...
    蜂猴阅读 937评论 0 0
  • Objc 相等性判断 今天做任务时遇到一个问题,情况是这样的:我新建一个类,然后创建一个这个类的对象,然后将这个类...
    凌巅阅读 1,496评论 0 1
  • 上周我们学校举行了一场运动会,在田径100米项目中,六名参赛选手中,有一位是黑人兄弟,站在站台观看比赛的我们一致认...
    幸福happy阅读 280评论 3 2