无论我们使用什么语言,总是会出现需要判断两个对象是否相等的情况,OC当然也不例外。首先看一段代码:

        NSString *str1 = [[NSString alloc] initWithCString:"equal" encoding:NSUTF8StringEncoding];
NSString *str2 = @"equal";
if(str1 == str2)
{
NSLog(@"equal");
}

很明显,在我们开来,str1和str2是“相等的”。但是事实上equal是不会被打印的。这是因为如果我们直接比较两个对象是否相等,实际上比较的是两个对象的指针是否相等。

上述代码中str1和str2是分别指向两块不同的内存的,所以肯定不会像等了。

我们稍微修改一下代码再看看:

        NSString *str1 = [[NSString alloc] initWithCString:"equal" encoding:NSUTF8StringEncoding];
NSString *str2 = @"equal";
if([str1 isEqual:str2])
{
NSLog(@"equal");
}

注意看加粗语句,我们改用NSObject提供的isEqual方法比较,发现"equal"被打印了出来。因为isEqual在NSString 内部被实现的时候比较的是真正的字符串是否相等!

对象等同性实现

看过上面例子后,现在我们自己创建一个类来进一步说明等同性

#import <Foundation/Foundation.h>

@interface EqualObject : NSObject

@property(nonatomic ,strong)NSString *name;

@end

#import "EqualObject.h"

@implementation EqualObject

@end

定义了一个EqualObject类,有一个name属性。

现在我们创建两个对象来比较一下:

 EqualObject *object1 = [EqualObject new];
EqualObject *object2 = [EqualObject new]; if([object1 isEqual:object2])
{
NSLog(@"equal");
}

发现代码运行结束并没有输出"equal",原因就在于isEqual方法是需要我们自己实现的。NSObject的isEqual:方法默认是比较两个对象指向的地址是否相等,这里开辟了两个对象肯定不想等了。

现在我们添加isEqual:方法的实现:

-(BOOL)isEqual:(id)object
{
if([self class] == [object class])
{
if(![self.name isEqual:[(EqualObject *)object name]])
{
return NO;
}
return YES;
}
else
{
return [super isEqual:object];
}
}

这里稍微解释一下,为什么两个对象不同类就调用父类的isEqual:这是因为,有的时候我们是可以让子类等于父类的,我们只需要关注属性是否相同时可以这样写,如果不需要也可以不在父类处理那么久默认不相等了。

现在我们不对name进行赋值操作依然是没有值打印出来的。

修改客户端代码:

        EqualObject *object1 = [EqualObject new];
EqualObject *object2 = [EqualObject new];
object1.name = @"xiaoming";
object2.name = @"xiaoming"; if([object1 isEqual:object2])
{
NSLog(@"equal");
}

发现这时候在运行就已经相等了。

为类定制等同性方法

我们可以看到NSString除了可以用isEqual比较是否相等意外,还可以使用isEqualToString来比较!这是专为NSString类定制的等同性方法,提供这样的方法就可以很明确我们实现了该对象的isEqual方法。

下面为EqualObject提供定制的等同性方法,并修改isEqual:方法

- (BOOL)isEqualToEqualObject:(EqualObject *)object
{
if(self == object)
return YES;
if(![self.name isEqualToString:object.name])
return NO;
return YES;
} - (BOOL)isEqual:(id)object
{
if([self class] == [object class])
{
return [self isEqualToEqualObject:object];
}
else
{
return [super isEqual:object];
}
}

然后客户端修改

        if([object1 isEqualToEqualObject:object2])
{
NSLog(@"equal");
}

很顺利的"equal"了...

对象hash码

每一个OC对象内部都是有一个hash码的,当对象存入集合中(Array,Set,HashTable等),那么他们的hash码会被当做键来决定他们该放入哪一个集合中。

首先我们先看一下集合内部是如何存储的

hashCode subCollection
code1 value1,value2,value3,value4
code2 value5,value6
code3 value7
code4 value8,value9,value10

集合的内部并不像我们所想的那样,是一个hash表,它将插入的对象根据hashCode来决定放入哪一个子集合。如果要删除或者比较集合内元素,它首先根据hashCode找到子集合,然后跟子集合的每个元素比较。

所以如果我们的对象的hashCode如果都相同,那么就会出现严重的效率问题,

理论上来说,我们确定等同性的两个对象的hash应该是相同的而不等的两个对象hash也应该不等,这样在存入hashTable之类的集合时,就 会避免相同对象的重复添加,比如我们两个对象hash相等,但实际对象不等,那么添加的时候就会被添加到同一subCollection下面。

所以为了避免这种情况,我们尽量自己实现一种避免重复的方式,

这里提供一种,添加一个新属性age,hash实现如下:

- (NSUInteger)hash
{
NSUInteger nameHash = [_name hash];
NSUInteger ageHash = _age;
return nameHash ^ ageHash;
}

集合中的对象等同性

我们对NSArray调用isEqual方法,它会对集合里的每个对象和另一个集合相同位置的对象进行isEqual:操作,只有全部相等,两个集合才相等。

这里说一下,集合里面最后添加都是不可变元素,如果是可变性元素会出现不法控制的情况。

比如我们往NSSet里面添加两个NSMutableArray,一开始两个array不等,那么set中就有两个元素。

然后修改一个array使两个相等,这是set中就会有两个相等的元素存在!

Objective-C——判断对象等同性的更多相关文章

  1. Effective Objective-C 2.0 — 第8条:理解“对象等同性”这一概念

    第8条:理解“对象等同性”这一概念 若想检测对象的等同性,请提供“isEqual”与 hash 方法 相同的对象必须具有相同哈希码,但是两个哈希码相同的对象却未必相同. 不要盲目地逐个检测每条属性,而 ...

  2. 如何理解iOS的“对象等同性”

    在iOS开发过程中,我们经常需要用到等同性来判断两个对象是否相等,通常我们会使用==来判断,但是这样比较出来的结果可能不是我们期望的:所以,一般我们会使用NSObject协议声明的isEqual方法来 ...

  3. 深入Java虚拟机--判断对象存活状态

    程序计数器,虚拟机栈和本地方法栈 首先我们先来看下垃圾回收中不会管理到的内存区域,在Java虚拟机的运行时数据区我们可以看到,程序计数器,虚拟机栈,本地方法栈这三个地方是比较特别的.这个三个部分的特点 ...

  4. js中判断对象具体类型

    大家可能知道js中判断对象类型可以用typeof来判断.看下面的情况 <script> alert(typeof 1);//number alert(typeof "2" ...

  5. java虚拟机判断对象是否存活的方式

    引用计数算法:   给对象添加一个引用计数器,每当有地方应用时,计数器值就加一,当引用失效时,程序计数器就减一,只要引用计数器的值为零时,就表示对象不可能再被引用,例如微软的 component ob ...

  6. 将对象的所有属性名放到一个数组中 || 获得对象的所有属性名 || return;不具有原子性 || 怎样自己制作异常|| 判断对象有没有某个属性 || 当传递的参数比需要的参数少的时候,没有的值会被赋予undefined || 获得函数实际传递的参数 || 怎么用函数处理一个对象 || 用一个名字空间定义一个模块所有的函数 || 给一个对象添加方法

    获得对象的所有属性名 || 将对象o的所有属性名放到数组中 var o = {x:1,y:2,z:3}; var arr = []; var i = 0; for(arr[i++] in o){};/ ...

  7. JavaScript中判断对象类型方法大全1

    我们知道,JavaScript中检测对象类型的运算符有:typeof.instanceof,还有对象的constructor属性: 1) typeof 运算符 typeof 是一元运算符,返回结果是一 ...

  8. freemarker判断对象是否为空

    freemarker中显示某对象使用 ${name}.   但如果name为null,freemarker就会报错.如果需要判断对象是否为空: <#if name??> …… </# ...

  9. 关于jquery判断对象是否为空

    1. jquery对象分为两种,一种是dom对象,dom对象会自带一个length属性,所以这种情况: obj.length == 0 可以判断对象为空 2. jquery也可以自定义对象,如 var ...

随机推荐

  1. 不可或缺的企业OA面临问题,以及解决建议 软件定制开发 森普演示平台

    ---恢复内容开始--- 随着信息时代的来临,企业管理也相应的信息化,各种管理软件相继而出,各行各业的信息化有过成功,也有过失败(注:是以该项目是否达到用户的预期目标而言).据统计在信息化失败的案例中 ...

  2. 通过项目逐步深入了解Mybatis<四>

    延迟加载 什么是延迟加载? resultMap可以实现高级映射(使用association.collection实现一对一及一对多映射),association.collection具备延迟加载功能. ...

  3. ThreadPool(线程池) in .Net

    本文来自:http://rickie.cnblogs.com/archive/2004/11/23/67275.html 在多线程的程序中,经常会出现两种情况.一种情况下,应用程序中的线程把大部分的时 ...

  4. 2014年百度之星资格赛第二题Disk Schedule

    Problem Description 有非常多从磁盘读取数据的需求,包含顺序读取.随机读取.为了提高效率,须要人为安排磁盘读取. 然而,在现实中,这样的做法非常复杂. 我们考虑一个相对简单的场景. ...

  5. 命令行分析java线程CPU占用

    1.使用top命令找出占用cpu最高的JAVA进程pid号 2. 找出占用cpu最高的线程: top -Hp  -n 1 3. 打印占CPU最高JAVA进程pid的堆栈信息 jstack pid &g ...

  6. Paxos算法深入分析

    在分布式系统设计领域,Paxos可谓是最重要一致性的算法.Google的大牛们称   All working protocols for asynchronous consensus we have ...

  7. Java并发编程学习笔记 深入理解volatile关键字的作用

    引言:以前只是看过介绍volatile的文章,对其的理解也只是停留在理论的层面上,由于最近在项目当中用到了关于并发方面的技术,所以下定决心深入研究一下java并发方面的知识.网上关于volatile的 ...

  8. 11g导入大量包含子分区的数据时表空间不足

    问题描述: ORACLE11g使用impdp数据泵导入时遭遇: ORA-01691: Lob 段 ISCS.SYS_LOB0000100750C00045$$ 无法通过 128 (在表空间 RT_DA ...

  9. [原创] Assistant editor 取消拖拽 binding 的 UI 元素

    1. press up-right button "show the utilities" 2. press "show the Connections inspecto ...

  10. mysql查询优化技巧

    索引优化,查询优化,查询缓存,服务器设置优化,操作系统和硬件优化,应用层面优化(web服务器,缓存)等等.这里记录的优化技巧更适合开发人员,都是从网络上搜集和整理的,主要是查询语句上的优化,其他层面上 ...