一、封装
理解封装
将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过该类所提供的方法来实现对内部信息的操作和访问。
对一个类或对象实现良好的封装,可以实现以下目的
- 隐藏类的实现细节
- 让使用者只能通过事先预定的方法来访问数据,从而可以在该方法里加入控制逻辑,限制对成员变量的不合理访问
- 可进行数据检查,从而有利于保证对象信息的完整性
- 便于修改,提高代码的可维护性
访问控制符
Objective-C提供了4个访问控制符:@private、@package、@protected 和 @public。访问控制符用于控制类的成员变量是否可以被其他类访问
- @private(当前类访问权限):成员变量只能在当前类的内部访问,在类实现部分定义的成员变量相当于默认使用了这种访问权限。
- @package(同映像访问权限):成员变量可以在当前类以及当前类实现的同一映像中使用(同一映像就是编译后生成的同一框架或同一个执行文件)。这个访问控制符用于部分隐藏成员变量。
- @protected(子类访问权限):成员变量可以在当前类、当前类的子类的任何地方访问。这个访问限制符用于部分暴露成员变量。在类接口部分定义的成员变量默认是这种访问权限。
- @public(公共访问权限):成员可以在任意地方访问。
二、继承
特点
- 继承可以实现代码的复用,减少代码冗杂。
- Objective-C中每个子类只有一个直接父类。
- 实现继承的类称为子类,被继承的类称为父类、基类、超类
- 子类可继承父类的全部成员变量、全部方法(包括初始化方法)
@interface Subclass : SuperClass
{
//成员变量定义
}
//方法定义
@end
重写父类的方法
- 重写父类方法时,子类接口部分不需要重新声明要重写的方法,只要在类实现部分直接重写该方法即可。
- 方法的重写必须注意方法签名关键字要完全相同,即方法名和方法签名中的形参标签都需要完全相同,否则不能算方法重写。
- 方法重写也可以称为方法覆盖。(可以说子类重写了父类的方法,也可以说子类覆盖了父类的方法)
super关键字
super是Objective-C提供的一个关键字,如果需要在子类方法中调用父类被覆盖的方法,使用super关键字来调父类被覆盖的方法。super用于限定该对象调用它从父类继承得到的属性或方法。
三、多态
理解多态
多态,即对于不同对象响应同一个方法时做出的不同反应。
Objective-C指针类型的变量有两个:编译时类型、运行时类型。编译时类型由声明该变量时所下使用的类型决定,运行时类型由实际赋给该变量的对象决定。如果编译时类型与运行时类型不一致,就有可能出现所谓的多态。
实现多态的前提
- 有继承关系
- 方法重写
- 父类指针指向子类对象
id类型
OC中提供了一个id类型,id类型的变量可被赋值给任意类型的指针变量,id类型的变量可以调用该变量实际所指对象的方法。 当通过id类型变量来调用方法时,OC将会执行动态绑定,动态绑定,是指oc将会跟踪对象所属类,它会在运行时判断该对象所属类,并在运行时确定需要动态调用的方法,而不是在编译时确定要调用的方法。
定义一个FKBase类,该FKBase类的接口部分如下:
#import <Foundation/Foundation.h>
@interface FKBase : NSObject
- (void) base;
- (void) test;
@end
FKBase类实现部分如下:
@implementation FKBase
- (void) base {
NSLog(@"父类的普通base方法");
}
- (void) test {
NSLog(@"父类的将!被覆盖的test方法");
}
@end
定义一个FKBase的子类FKSubclass,该子类将会覆盖父类中定义的test方法。
接口部分如下:
#import <Foundation/Foundation.h>
#import "FKBase.h"
@interface FKSubclass : FKBase
- (void) sub;
- @end
FKSubclass实现部分如下:
#import <foundation/Foundation.h>
#import "FKSubclass.h"
@implementation FKSubclass
- (void) test { //重写父类test方法
NSLog(@"子类的覆盖父类的test方法");
}
- (void) sub {
NSLog(@"子类的sub方法");
}
@end
程序如下:
#import <Foundation/Foundation.h>
#import "FKSubclass.h"
int main(int argc, char * argv[]) {
@autoreleasepool {
//下面编译时类型和运行时类型一样,不存在多态
FKBase* bc = [[FKBase alloc] init];
//下面两行调用FKBase的方法
[bc base];
[bc test];
//下面编译时类型与运行时类型一样,不存在多态
FKSubclass* sc = [[FKSubclass alloc] init];
//下面调用将执行从父类继承的base方法
[sc base];
//下面调用将执行子类重写的test方法
[sc test];
//下面调用执行子类定义的sub方法
[sc sub];
//下面编译时类型与运行时类型不一样,发生多态
FKBase* ploymophicBc = [[FKSubclass alloc] init];
//下面调用将执行从父类继承到的base方法
[ploymophicBc base];
//下面调用将执行子类重写的test方法
[ploymophicBc test];
//[ploymophicBc sub] 编译时会出错
//因为ploymophicBc的编译类型是FKBase,FKBase类没有提供sub方法,所以编译会出错
id dyna = ploymophicBc;
[dyna sub];
}
}
该程序中指针变量ploymophicBc编译时类型是FKBase,运行时类型时FKSubclass,当该指针变量调用test方法时(FKBase类中定义了该方法,FKSubclass子类重写了父类该方法),实际上执行的是FKSubclass类中覆盖后的test方法,这就可能出现多态。