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

来源:互联网 发布:一个域名成就一个梦想 编辑:程序博客网 时间:2024/06/05 13:31

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的三大特性概述完毕。几笔内容多为老师重点和随堂抄写。方便记忆和加深理解。





0 0
原创粉丝点击