OC语言之封装,继承,多态

时间:2021-01-22 21:54:54

封装

##1.面向对象三大特性

封装性

继承性

多态性

---

##2.什么是封装

封装性就是隐藏实现细节,,仅对外公开接口。

![](http://7xj0kx.com1.z0.glb.clouddn.com/01300000241358127703362578572.jpg)

![](http://7xj0kx.com1.z0.glb.clouddn.com/163157537.jpg)

---

##3.为什么要进行封装?

以下代码存在的问题?

```

// 1成员变量是public,也就是公开的,我们不能控制外界如何赋值外界有可能赋值一些脏数据

@interface Gun : NSObject

{

    @public// 公开成员变量

    int _bulletCount;// 子弹数量

}

@end

// 可以利用封装来解决这个问题

// 封装:是指隐藏对象的属性和实现的细节,仅对外提供公共的访问方法

```

类是数据与功能的封装,数据就是成员变量,功能就类方法或对象方法

对数据的封装,也就是对成员变量的封装

不封装的缺点:当一个类把自己的成员变量暴露给外部的时候,那么该类就失去对该成员变量的管理权,别人可以任意的修改你成员变量。

封装就是将数据隐藏起来,只能用此类的方法才可以读取或者设置数据,不可被外部任意修改是面向对象设计本质。降低了数据被误用的可能性,提高代码的灵活性

---

##4.封装的好处

好处

    + 将变化隔离

    + 提高安全性

原则

    + 将不需要对外提供的内容都隐藏起来,把属性都隐藏,提供公共的方法对其访问

---

依赖关系

##1.依赖关系

可以简单的理解,就是一个类A使用到了另一个类B,而这种使用关系是具有偶然性的、临时性的、非常弱的,但是B类的变化会影响到A

    + 比如某人要过河,需要借用一条船,此时人与船之间的关系就是依赖;

iOS中表现在代码层面,为类B作为参数被类A在某个method方法中使用;

 

继承

##1.继承基本概念

现实生活中的继承

![](http://7xj0kx.com1.z0.glb.clouddn.com/Snip20150530_2.png)

![](http://7xj0kx.com1.z0.glb.clouddn.com/jcjgt.png)

交通工具类是一个基类(也称做父类),通常情况下所有交通工具所共同具备的特性,如速度与额定 载人的数量

按照生活常规,我们来继续给交通工具来细分类的时候,我们会分别想到有汽车类和飞机类等 等,汽车类和飞机类同样具备速度和额定载人数量这样的特性,而这些特性是所有交通工具所共有的,那么就可以让汽车或飞机类继承交通工具类,这样当建立汽车类和飞机类的时候我们无需再定义交通工具类(基类)中已经有的成员和方法,而只需要�述汽车类和飞机类所特有的特性即可。

飞机类和汽车类的特性是由在交通工具类原有特性基础上增加而来的,那么飞机类和汽车类就是交通工具类的派生类(也称做子类)。以此类推,层层递增这种子类获得父类特性的概念就是继承

继承的重要性

![](http://7xj0kx.com1.z0.glb.clouddn.com/Snip20150530_3.png)

---

##2.OC中的继承关系

![](http://7xj0kx.com1.z0.glb.clouddn.com/jcjg3.png)

- B类继承A类,那么B类将拥有A类的所有属性和方法,此时我们说A类是B类的父类,B类是A类的子类

- C类继承B类,那么C类将拥有B类中的所有属性和方法,包括B类从A类中继承过来的属性和方法,此时我们说B类是C类的父类,C类是B类的子类

注意:

    + 基类的私有属性能被继承,不能在子类中访问。

    + OC中的继承是单继承:也就是说一个类只能一个父类,不能继承多个父类

    + 子类与父类的关系也称为isA(是一个)关系,我们说 子类isA父类,也就是子类是一个父类,比如狗类继承动物类,那么我们说狗isA动物,也就是狗是一个动物。在如汽车继承交通工具,那么们说汽车isA交工工具,也就是汽车是一个交通工具

    + 继承的合理性:引用《大话西游》里的一句话来描述继承的。“人是人他妈生的,妖是妖他妈生的!

---

##3.OC中如何实现继承

在声明子类的时候,在子类名称后面通过:父类名称方式来实现继承

```

@interface 子类名称 父类名称

@end

---

继承相关特性

##1.方法重写

在子类中实现与父类中同名的方法,称之为方法重写;

重写以后当给子类发送这个消息的时候,执行的是在子类中重写的那个方法,而不是父类中的方法。

如果想在子类中调用被子类重写的父类的方法,可以通过super关键字

使用场景:当从父类继承的某个方法不适合子类,可以在子类中重写父类的这个方法。

##2.继承中方法调用的顺序

- 1、在自己类中找

- 2、如果没有,去父类中找

- 3、如果父类中没有,就去父类的父类中

- 4、如果父类的父类也没有,就还往上找,直到找到基类(NSObject)

- 5、如果NSObject都没有就报错了

    >+ 如果找到了就执行这个方法,就不再往后查找了

---

##3.继承的注意事项

子类不能定义和父类同名的成员变量,私有成员变量也不可以;因为子类继承父类,子类将会拥有父类的所有成员变量,若在子类中定义父类同名成员变量 属于重复定义。

- OC类支持单一继承,不支持多继承;也就是说一个类只能有一个直接父类

- OC类支持多层继承 ,如下图所示

![](http://7xj0kx.com1.z0.glb.clouddn.com/djc.png)

多态基本概念

##1.什么是多态?

什么是多态:多态就是某一类事物的多种形态

    + -->动物

    + -->动物

    + 男人 男人 -->人 -->高级动物

    + 女人 女人 -->人 -->高级动物

程序中的多态:父类指针指向子类对象

---

##2.多态的条件

有继承关系

子类重写父类方法

父类指针指向子类对象

```

狗 *g = [狗 new];

动物 *a = [狗 new];

猫 *c = [猫 new];

动物 *a = [猫 new];

```

表现:当父类指针指向不同的对象的时候,通过父类指针调用被重写的方法的时候,会执行该指针所指向的那个对象的方法

---

##3.多态的优点

多态的主要好处就是`简化了编程接口。`它允许`在类和类之间重用一些习惯性的命名,`而不用 为每一个新加的函数命名一个新名字。这样,编程接口就是一些抽象的行为的集合,从而和实现接口的类的区分开来。

多态也使得代码可以分散在不同的对象中而不用`试图在一个函数中考虑到所有可能的对象。这样使得您的代码扩展性和复用性更好一些。当一个新的情景出现时,您无须对现有的代码进行 改动,而只需要增加一个新的类和新的同名方法。

---

多态的实现

##1.如何实现多态

- Animal是父类,子类有Cat 和 Dog,子类分别重写了父类中的eat方法;实例化对象的时候可以用下面的方法:

```

Animal *animal = nil;

//实例化猫的对象

animal = [Cat new];

[animal eat];

//实例化狗的对象

animal = [Dog new];

[animal eat];

```

##2.多态的原理

动态绑定:

    + 动态类型能使程序直到执行时才确定对象的真实类型

    + 动态类型绑定能使程序直到执行时才确定要对那个对象调用的方法

- OC不同于传统程序设计语言,它可以在运行时加入新的数据类型和新的程序模块:动态类型识别,动态绑定,动态加载

- id类型:通用对象指针类型,弱类型,编译时不进行具体类型检查

---

##3.多态的注意点

- 1)如果存在多态,父类是可以访问子类特有的方法

假设 子类 Dog 有一个特有的方法bark

[dog bark];

Animal *an2 = [Dog new];

[(Dog*)an2 bark]; //把父类的指针,强制类型转换

```

- 2)如果不存在多态,父类是不可以访问子类特有的方法的

```

Animal *an3 = [Animal new];

[(Dog*)an3 bark]; //错误的,不能强制转换

```

自定义代码段

##1.如何自定义代码片段

将代码拖拽到code区域

![](http://7xj0kx.com1.z0.glb.clouddn.com/Snip20150529_23.png)

配置快捷键等信息

![](http://7xj0kx.com1.z0.glb.clouddn.com/Snip20150529_27.png)

使用快捷键

![](http://7xj0kx.com1.z0.glb.clouddn.com/Snip20150529_31.png)

![](http://7xj0kx.com1.z0.glb.clouddn.com/Snip20150529_32.png)

练习自定义get方法快捷键

![](http://7xj0kx.com1.z0.glb.clouddn.com/Snip20150529_28.png)

![](http://7xj0kx.com1.z0.glb.clouddn.com/Snip20150529_30.png)

---

##2.如何导入代码片段

将下载好的代码片段拷贝到:`/Users/LNJ/Library/Developer/Xcode/UserData/CodeSnippets`

    + 注意将`LNJ`换为自己的用户名

![](http://7xj0kx.com1.z0.glb.clouddn.com/Snip20150529_33.png)

 

点语法

##1.点语法基本使用

---

##2.点语法的本质

其实点语法的本质还是方法调用

当使用点语法时,编译器会自动展开成相应的方法

![](http://7xj0kx.com1.z0.glb.clouddn.com/dyf.png)

当点语法使用在 “=“赋值符号左侧的时候,点语法会被展开为setter方法的调用,其他情况(等号右侧、直接使用)为点语法展开为getter方法的调用

---

##3.点语法注意

点语法的本质是方法的调用,而不是访问成员变量,当使用点语法时,编译器会自动展开成相 应的方法调用。

切记点语法的本质是转换成相应的对settergetter方法调用,如果没有setget方法,则不能使用点语法。

不要在getter 与  setter方法中使用本属性的点语法

```

- (void) setAge:(int)age {

    // 下面的代码会引发死循环

    self.age = age;

        //编译器展开后 [self setAge:age]

}

- (int) age {

    // 下面的代码会引发死循环

    return self.age;

          // 编译器展开后 [self   age]

}

--

实例变量修饰符

##1.实例变量的作用域

![](http://7xj0kx.com1.z0.glb.clouddn.com/slblxsf.png)

- 1)@public (公开的)在有对象的前�下,任何地方都可以直接访问。

- 2)@protected (受保护的)只能在当前类和子类的对象方法中访问

- 3)@private (私有的)只能在当前类的对象方法中才能直接访问

- 4)@package (框架级别的)作用域介于私有和公开之间,只要处于同一个框架中相当于@public,在框架外部相当于@private

---

##2.变量修饰符在子类中的访问

- 1)@private私有成员是能被继承,也不能被外部方法访问。

- 2)@public 公有成员能被继承,也能被外部方法访问。

- 3)@protected 保护成员能够被继承,不能够被外部方法访问。

---

##3.实例变量作用域使用注意事项

- (1)@interface @end之间声明的成员变量如果不做特别的说明,那么其默认是protected 的。

- (2)一个类继承了另一个类,那么就拥有了父类的所有成员变量和方法,注意所有的成员变量它都拥有,只是有的它不能直接访问。例如@private

---

# description方法

##1.description基本概念

- NSLog(@"%@", objectA);这会自动调用objectAdescription方法来输出ObjectA的描述信息.

- description方法默认返回对象的描述信息(默认实现是返回类名和对象的内存地址)

- description方法是基类NSObject 所带的方法,因为其默认实现是返回类名和对象的内存地址这样的话,使用NSLog输出OC对象,意义就不是很大,因为我们并不关心对象的内存地址,比较关心的是对象内部的一些成变量的值。因此,会经常重写description方法,覆盖description方法 的默认实现

---

##2.description重写的方法

对象方法

```

/**对象方法:当使用NSLog输出该类的实例对象的时候调用*/

-(NSString *) description

{

    return [NSString stringWithFormat:@"狗腿数:%d,狗眼数%d\n",_legNum,_eyeNum];

}

```

类方法

```

/**类方法:当使用NSLog输出该类的类对象的时候调用*/

+(NSString *) description

{

    return @"+开头的description方法";

}

```

##3.description陷阱

千万不要在description方法中同时使用%@self,下面的写法是错误的

```

- (NSString *)description {

    return [NSString stringWithFormat:@"%@", self];

}

```

同时使用了%@self,代表要调用selfdescription方法,因此最终会导致程序陷入死循环,循 环调用description方法

[NSString stringWithFormat:@%@, self]; 使用它时,循坏调用,导致系统会发生运行时错误。

当该方法使用NSLog(%@,self)  时候系统做了相关的优化,循坏调用3次后就会自动退出

---

# getter/setter方法

##1.setter方法

作用:用来设置成员变量,可以在方法里面过滤掉一些不合理的值

命名规范:

    + 必须是对象方法

    + 返回值类型为void

    + 方法名必须以set开头,而且后面跟上成员变量名去掉”_” 首字母必须大写

    + 必须提供一个参数,参数类型必须与所对应的成员变量的类型一致

    + 形参名称和成员变量去掉下划线相同

举例:

```

如:如果成员变量为int _age 那么与之对应seter方法为

-(void) setAge: (int) age;

```

- setter方法的好处

    + 不让数据暴露在外,保证了数据的安全性

    + 对设置的数据进行过滤

---

##2.getter方法

作用:为调用者返回对象内部的成员变量的值

命名规范:

    + 必须是对象方法

    + 必须有返回值,返回值的类型和成员变量的类型一致

    + 方法名必须是成员变量去掉下划线

    + 一定是没有参数的

举例

```

如:如果成员变量为int _age 那么与之对应geter方法为

- (int) age;

```

- getter方法的优点:

    + 可以让我们在使用getter方法获取数据之前,对数据进行加工;

    + 比如双十一活动,我们希望对全线商品的价格在原来的价格基础上打五折,那么我们只要去改成品类的价格的getter方法就可以了,让他返回的值为价格 * 0.5

---

##3.getter/setter方法注意

在实际的开发中,不一定setget方法都会提�供,如果内部的成员变量,比如学生的学号或计算出来的数据。这样的数据只允许外界读取,但是不允许修改的情况,则通常只提�供get方法而不�提供set方法

成员变量名的命名以下划线开头,get方法名不需要带下划线

成员变量名使用下划线开头有两个好处

    + get方法的方法名区分开来

    + 可以和一些其他的局部变量区分开来,下划线开头的变量,通常都是类的成员变量。当我看到以下划线开头变量,那么他一定是成员变量

---

##4.练习

设计一个K线类有三个属性最高价格最低价格平均价格要求可以设置和获取这三个属性

 

# Self关键字

- OC提�供了两个保留字selfsuper

    + OC语言中的self,就相当于C++Java中的this指针。

要理解什么是self,什么是成员变量,什么是对象方法,什么是类方法

成员变量:成员变量是一个实例对象的具体状态特征,并且这些状态特征是可以改变的,如张三的年龄,身高,体重等

对象方法:一个实例对象的行为,比如张三具有吃的行为,张三做出这样行为的时候,有可能会影响,自身的某些状态特征,比如张三吃可能会增加张三体重和身高。

类方法:类方法是某个类的行为,可以直接通过类名调用;如果在类方法中需要使用某些数据,必须通过参数传入;它不能访问成员变量。

---

##1.类方法中的self

在整个程序运行过程中,`一个类有且仅有一个类对象`

通过`类名`调用方法就是给这个`类对象`发送消息。

类方法的self就是这个类对象

在类方法中可以通过self来调用其他的类方法

不能在类方法中去调用对象方法或成员变量,因为对象方法与成员变量都是属于具体的实例对象的。

// 缺一张配图

---

##2.对象方法中的self

在整个程序运行过程中,`对象可以有0个或多个`

通过`对象`调用方法就是给这个`对象`发送消息

对象方法中self就是调用这个方法的当前对象。

在对象方法中,可以通过self来调用本对象上的其他方法

在对象方法中,可以通过self来访问成员变量

// 缺一张配图

---

##3.全局变量成员变量局部变量

全局变量:只要是有声明它的地方都能使用

成员变量:只能在本类和其子类的对象方法中使用

局部变量:只能在本函数或方法中使用

从作用域的范围来看:全局变量 成员变量 局部变量

当不同的作用域中出现了同名的变量,内部作用域的变量覆盖外部作用域变量,所以同名变量的覆盖顺序为:局部变量覆盖成员变量,成员变量覆盖全局变量

如果在对象方法中出现与成员变量同名的局部变量,如果此时想使用该成员变量可以通过self->成员变量名的方式

---

##4.self总结

谁调用self所在的方法,那么self就是谁

- self在类方法中,就是这个类的类对象,全局只有一个,可通过self调用本类中的其他类方法,但是不能通过self来调用对象方法或访问成员变量

- self在对象方法中,就是调用这个方法的那个对象, 可以通过self调用本类中其他的对象方法,访问成员变量,但不能通过self调用本类的类方法。

通过self调用方法的格式:[self  方法名];

通过self访问成员变量格式:self->成员变量名

---

##5.self使用注意

同时有对象方法和类方法存在的时候,self不会调错

- self只能在方法中使用;不要使用self来调用函数,也不可以在函数内部使用self

使用self调用本方法,导致死循环调用。

---

# Super关键字

##1.super基本概念

- super是个编译器的指令符号,只是告诉编译器在执行的时候,去调谁的方法.

    >+ self是一个隐私参数;

```

self refers to the object receiving a message in objective-C programming.

```

    >+ super 并不是隐藏的参数,它只是一个“编译器指示符”,它和 self 指向的是相同的消息接收者

```

super is a flag that tells the compiler to search for the method implementation in a very different place. It begins in the superclass of the class that defines the method where super appears.

```

##2.super的作用

    + 1.直接调用父类中的某个方法

    + 2.super在对象方法中,那么就会调用父类的对象方法

     super在类方法中,那么就会调用父类的类方法

使用场合:

    + 子类重写父类的方法时想保留父类的一些行为