您的位置:首页 > 职场人生

黑马程序员_OC面向对象的三大特性

2015-04-02 15:12 190 查看
OC语言中面向对象有三大特性,分别是封装,继承和多态。

(一)封装:

在上次的笔记中,我学到了类的成员变量有四种作用域类型,分别是@public,@private,@protected和@package。
之前我们定义好成员变量后,想要在main中直接访问成员变量,往往要在成员变量的定义时候加上一个@public,这种
做法虽然可以实现访问,可是它会让你的数据变得很透明,不仅可以随意被访问而且有可能会变得很不合理,例如我顶
一个一个int类型的age年龄属性,在主函数main中把age赋值成-10,这都是可以的。所以,为了保证数据的不透明习
惯,安全性和合理性。我们一般不适用@Public来使得外界获得访问权利。而是提供一种封装方法来供外界使用访问我
们内部的成员变量。这些方法成为setter和getter。它们就是我们的封装。

1.setter和getter的声明:

<div style="text-align: justify;"><span style="font-size:18px; font-family: Arial, Helvetica, sans-serif;">@interface Person : NSObject</span></div><span style="font-size:18px;">{
int _age;
}
</span><div style="text-align: justify;"><span style="font-family: Arial, Helvetica, sans-serif;">t)age;
- (int)age;
@end</span></div>- (void)setAge:(i
<div style="text-align: justify;"><span style="font-family: Arial, Helvetica, sans-serif;">n</span></div>


由上我们可以总结setter和getter的声明规范和一些注意点。首先,setter是更改成员变量属性,所以不需要返回值并且
一定要传入一个和成员变量数据类型相同的参数。同时遵循方法命名规范:一个参数一个分号,数据类型用小括号括起
来。而getter的作用是获得成员变量的值,所以不需要传入参数,并且一定有返回值,返回值为成员变量的数据类型。
我们定义的成员变量是已下滑线开头的,它相应的getter和setter则不需要下划线。

2.setter和getter的实现:

<div style="text-align: justify;"><span style="font-size:18px; font-family: Arial, Helvetica, sans-serif;">#import "Person.h"</span></div><span style="font-size:18px;"></span><div style="text-align: justify;"><span style="font-family: Arial, Helvetica, sans-serif;">@implementation Person</span></div><div style="text-align: justify;"><span style="font-family: Arial, Helvetica, sans-serif;">- (void)setAge:(int)age</span></div>{
if (age<=0)
<div style="text-align: justify;"><span style="font-family: Arial, Helvetica, sans-serif;">   _age = age;
</span></div>        age = 1;

}
- (int)age
{
<div style="text-align: justify;"><span style="font-family: Arial, Helvetica, sans-serif;">end</span></div>    return _age;
}
<div style="text-align: justify;"><span style="font-family: Arial, Helvetica, sans-serif;">@</span></div>


由上我们可以总结setter和getter方法的实现规范。它们可以依靠代码来实现访问或者修改我们的内部成员变量的值。基
本上,每定义一个成员变量,都要设置其相应的setter和getter方法。

3.Xcode高级功能自动实现setter和getter:

①自动生成get方法和set方法:

@property int age;

其实编译器是很“笨”的,你怎么写他就怎么生成。写如上代码,编译器看到后,就自动变成

- (void)setAge:(int)age;

- (int)age;

相应的,它也完成了setter和getter方法的实现。

- (void)setAge:(int)age

{

_age = age;

}

- (int)age

{

return _age;

}

Xcode遵循一点,“没有我就生成,有我就用你的”。当什么都不定义就一句@property int age时,其实完成了三件事

定义了一个_age的成员变量。

声明了这个成员变量的getter和setter。

实现了这个成员变量的getter和setter。

②@synthesize是用于生成getter和setter的实现的。用在@implementation和@end之间。

@implementation Person

@synthesize age = _age;

@end

我们分析下这句@synthesize age = _age; --->第一个age表示实现age这个成员变量的set和get。后面的_age表示在实
现中,访问_age。

如果只写@synthesize age;就默认访问age而不是_age;如果此时没有写成员变量,就生成成员变量age。

③注意:
Xcode帮我们能够生成_age的原因是它要在get和set中访问调用。如果只写了set和get方法中的一个,另一个自动生
成。则Xcode依旧自动生成_age。但是如果set和get方法都是自己写的,那就不会再生成了。

在OC编程学习中,用的最多的还是@property。它可以生成下划线成员变量,getter,setter方法的声明和实现。并且遵
循我们习惯的书写规范(成员变量下划线开头)。剩下的仅作为了解。用了Xcode高级功能封装数据,可以节约出很多
写垃圾代码的时间,把更多的时间集合在思想上。

4.如果一个成员变量只允许访问不允许修改,那么这个成员变量就是只读的。这时候我们只提供它的get方法不提供set
方法就可以了。

5.OC的弱语法性:

①如果调用一个不存在的方法,编译可以通过,链接也可以通过,但是不能运行成功,会报一个经典的错误:unrecogined selector sent to intance。意思是给某个对象发送了一条不可识别的消息(方法)。这是一个编程中很
经常遇到的错误。
[1 2] --->2去1里找方法,找不到就报错。
②如果只写了方法声明,没有写实现,编译链接是可以通过的。OC是在运行工程中才会检测对象有没有实现相应的方
法。这时候会出现崩溃或者闪退现象。

③如果只写实现,不写声明。程序是可以运行成功的,但是不推荐。

④OC的本质还是面向过程的。

6.类方法:

①之前我们学习过以-开头的方法。这些方法都是由对象调用的,叫做对象方法。以+开头的是类方法。顾名思义,类方
法由类来调用。类方法无需创建对象。不依赖于对象就能实现方法,所以某种程度上提高了性能。例如我要设计计算器
的些许功能,求和求平方等等,这时候不需要成员变量的参与。这些方法都是类方法。

②类方法里只有方法,没有成员变量。所以类方法是决不能访问成员变量的。并且类方法和对象方法允许同名。

③类方法里自己调用自己,顾名思义,会产生死循环。

7.关键字self:

self是一个指针,指向调用当前方法的对象。说白了,就是当前对象/当前类。熟悉运用self,会感觉OC写起来“很方便”

使用 "self->成员变量名"访问当前方法调用的成员变量

使用 "[self方法名];"来调用方法(对象方法\类方法)

(二)继承:

继承其实并不陌生。@interface Car :NSObject 我们每次在创建类时候都要写一个:NSObject。这就是一个继承。
NSObject是Car的父类,也叫做超类。如果A继承B,那么A就拥有了B的所有属性,包括成员变量和所有方法。

@interfacePerson : NSObject

1.继承的好处和坏处:

①抽取重复代码。

②建立了类之间的关系。

③耦合性太强,两个类关系太密切。某个类不见了,另一个也就不能用了。所以说不是什么都可以随便继承。

2.之前我们通过new这个方法来实现类对对象的创建。其实new就是NSObjet的一个+类方法,通过继承,子类可以通过
new方法获得创造对象的能力。
3.能否继承,可以套用一句话,A 是 B。例如学生是人,那么学生类就可以拥有人这个类的所有属性。如果不适用,那
一般都不能继承。

4.因为子类继承父类,所以继承关系的类之间不允许拥有相同的成员变量,这样会产生重复定义的错误。

5.一个方法:重写-->子类重新实现父类的某个方法,覆盖父类以前的做法。调用某个对象方法时,优先是在当前对象中
找方法。当前对象中没有才去父类中寻找。下面由代码完成重写:

①首先定义Person类

#import <Foundation/Foundation.h>

@interface Person :NSObject

- (void) test;

@property int age;

@end

#import "Person.h"

@implementation Person

- (void) test

{

NSLog(@"我是Person父类");

}

@end

②定义Student类继承Person类

#import "Person.h"

@interface Student :Person

@end

#import "Student.h"

@implementation Student

- (void) test

{

NSLog(@"我是sTUDENT子类");

}

@end

由上代码。Student重写了Person的test函数。我们调用Student的test方法完成程序的执行。

#import <Foundation/Foundation.h>

#import "Person.h"

#import "Student.h"

int main()

{

Student *s = [Student new];

[stest];

return
0;

}

执行结果:

2015-04-02 16:18:58.507 oo[734:136700]我是sTUDENT子类


若要是不重写test方法,则现在当前类Student中找test方法,没有后去父类Person中找,找到后完成程序的执行。

执行结果:

2015-04-02 16:18:58.507 oo[734:136700]我是sTUDENT子类



至此,我们了解到了重写的功能。他可以覆盖父类功能。但是并不删除父类的功能。甚至可以先调用父类功能在重写此
功能。

6.继承和组合:

当两个类拥有相同的属性和方法时候,就可以把他们相同的东西抽到一个父类中。

当A类完全拥有B的属性时,例如人完全拥有学生的属性,那么学生就继承人

总的来说,子类的东西都要比父类多。因为可以再继承父类的基础上自己增加新的成员变量。

但不是一可以继承就是用继承,还有一种方法叫做组合。当A拥有B时,就是组合-->学生拥有成绩,他们的关系应该是组合。

组合指的是两个类不继承,但是一个类中得成员变量是另一个类。如下代码:

创建Student类继承Person,但是组合Score类

#import "Person.h"

#import "Score.h"

@interface Student : Person

{

NSString *_name;

Score *_score;

}

@end

Score类的声明:

#import <Foundation/Foundation.h>

@interface Score :
NSObject

{

int _cScore;

int _ocScore;

}

@property int cScore;

@property int ocScore;

@end

这样,Student类就拥有了Score成绩类的属性。到时候只需创建成绩对象,把成绩对象通过setScore的方法赋值给
Student的成绩成员变量就可以了。

7.继承关键字super

super是父类的意思。用来调用父类的对象方法或类方法。当子类重写父类时,若想要保留父类的行为,往往用super。
这时候我们再次重写一下上面的Student类中得test方法,代码如下:

#import "Student.h"

@implementation Student

- (void) test

{

[super test];

NSLog(@"我是sTUDENT子类");

}

@end

程序输出结果为:

2015-04-02 16:35:58.970 oo[770:148770]我是Person父类

2015-04-02 16:35:58.971 oo[770:148770]我是sTUDENT子类
由此可见super的使用方法。

(三)多态:

多态是多种形态的意思。指的是父类指针指向子类对象的行为。例如上述的Student类继承Person类。

1.多态的定义实现如下:

Person *p = [Student new];

NSObject *n = [Person new];

NSObject *n1 = [Student new];

代码执行后,会动态检测指针的真实类型。所以其实p还是学生类,n是人类型,n1是学生类型。

2.多态的好处:

使用多态后,函数里可以写入方法。当有猫,狗,鸟等等动物类时,若要想用一个函数实现吃这个行为。只需传入一个
他们共同的父类Animal动物类,这样所有类都可以使用这个方法了。

void feed(Animal *a)

{

[a eat];

}

这时候传入参数可以是任意动物类的子类。

3.多态的坏处:

不可以使用父类指针调用子类方法。会警告。编译器会认为这个指针是Anmial类型,是一个父类类型。从而去父类中寻
找方法。但是方法是在子类中的。这种方法不推荐。

4.多态总结


无继承无多态。

代码体现:父类指针指向子类对象。

好处:函数/方法参数可以使用父类类型。

坏处:父类指针不可调用子类方法,除非强转。

至此,OC的三大特性概述完毕。几笔内容多为老师重点和随堂抄写。方便记忆和加深理解。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息