无论我们使用什么语言,总是会出现需要判断两个对象是否相等的情况,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. 用Python实现九九乘法表

    1.用“#”组成的矩形的实现 代码 eight = int(input("Height:")) #用户输入高度 width = int(input("Width:&quo ...

  2. Oracle游标动态赋值

    1. oracle游标动态赋值的小例子 -- 实现1:动态给游标赋值 -- 实现2:游标用表的rowtype声明,但数据却只配置表一行的某些字段时,遍历游标时需fetch into到精确字段 CREA ...

  3. IT人士的职业规范——凝视

     这两天将系统敲完了,该总体调试了,调试的过程中,发现了一个非常大的问题,就是自己的凝视写的不够,有时候不明确U层这个事件是做什么的,有时候不知道这个事件传递的是什么參数,有时候不知道相应的B层和 ...

  4. Js apply 方法 具体解释

    Js apply方法具体解释 我在一開始看到javascript的函数apply和call时,很的模糊,看也看不懂,近期在网上看到一些文章对apply方法和call的一些演示样例,总算是看的有点眉目了 ...

  5. PHP反射ReflectionClass、ReflectionMethod 入门教程

    PHP反射ReflectionClass.ReflectionMethod 入门教程 作者:SNSGOU 发布于:2014-03-16 16:44:00  分类:PHP   浏览(6145) PHP5 ...

  6. ECSHOP首页站内快讯在哪里添加和修改?

    “添加新闻后在首页站内快讯处显示不出来?”.“请问首页中站内快讯(最新文章)在后台哪个位置管理”.“如何让发布的文章进入首页站内快讯”等等诸如此类的问题,经常在论坛里看到一些朋友在询问. 本ECSHO ...

  7. LINQ 操作符(二)

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  8. ios9基础知识(UI)总结

    UIWindow.UILabel.UIColor.UIScreen.UIViewController.UIView.UIControl.UIButton.IBOutlet.IBAction.UISte ...

  9. C++程序设计实践指导1.7超长数列中n个数排序改写要求实现

    改写要求1:将以上程序改写为适合超长整数 改写要求2:将以上程序改写为适合超长数列 改写要求3:将数列中指定位置m开始的n个结点重新按降序排序 改写要求4:输出指定位置m开始的n个结点的超长整数 #i ...

  10. OpenRisc-40-or1200的MMU模块分析

    引言 MMU(memory management unit),无论对于computer architecture designer还是OS designer,都是至关重要的部分,设计和使用的好坏,对性 ...