------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -----
第一讲 多态的介绍
本小节知识点:
1、【了解】什么是多态?
2、【掌握】多态的条件
3、【了解】多态的优点
提出一个问题:
大家来根据现在学习的知识,思考一个问题:父类能否访问子类方法?
1、什么是多态?
什么是多态:多态就是某一类事物的多种形态
猫: 猫 -->动物
狗: 狗 --> 动物
男人: 男人 --> 人 ---> 高级动物
女人: 女人 --> 人 ---> 高级动物
程序中的多态:不同的对象以自己的方式相应相同名称方法的能力称为多态。
2、多态的条件
多态的条件:有继承关系、有方法重写
父类的生命变量指向子类对象。
//代码体现:用父类类型的指针类型指向了子类对象,这就是多态
狗 *g = [狗 new];
动物 *a = [狗 new];
猫 *c = [猫 new];
动物 *a = [猫 new];
3、多态的优点
多态的主要好处就是简化了编程接口。它容许在类和类之间重用一些习惯性的命名,而不用为每一个新加的函数命名一个新名字。这样,编程接口就是一些抽象的行为的集合,从而和实现接口的类的区分开来。
多态也使得代码可以分散在不同的对象中而不用试图在一个函数中考虑到所有可能的对象。这样使得您的代码扩展性和复用性更好一些。当一个新的情景出现时,您无须对现有的代码进行改动,而只需要增加一个心得类和新的同名方法。
第二讲 多态的概念和条件
本小节知识点:
1、【掌握】如何实现多态
2、【了解】多态的原理
1、如何实现多态
Animal是父类,子类有Cat 和Dog,子分别重写了父类中的eat方法;实例化对象的时候可以用下面的方法:
Animal *ani = nil;
//实例化猫的对象
ani = [Cat new];
[ani eat];
//实例化狗的对象
ani = [Dog new];
[ ani eat];
2、多态的原理
动态绑定:
动态类型能使程序直到执行时才确定对象所属类型。
动态类型绑定能使程序直到执行时才确定要对对象调用的实际方法。
OC不同于传统程序设计语言,它可以在运行时加入新的数据类型和新的程序模
块:动态类型识别,动态绑定,动态加载。
id类型:通用指针类型,弱类型,编译时不进行类型检查。
3、多态的注意点
1)如果存在多态,父类可以访问子类特有的方法。
假设 子类 Dog 有一个特有的方法bark
[dog bark];
Animal *an2 = [Dog new];
[(Dog *)an2 bark]; //把父类的指针,强制类型转换
2)如果不存在多态,父类是不可以访问子类特有的方法的
Animal *an3 = [Animal new];
[(Animal *)an3 bark]; //错误的,不能强制转换
1 #import <Foundation/Foundation.h> 2 3 @interface Animal : NSObject 4 -(void)run; 5 @end 6 7 #import "Animal.h" 8 9 @implementation Animal 10 -(void)run{ 11 12 NSLog(@"动物在跑"); 13 } 14 @end 15 16 #import "Animal.h" 17 18 @interface Cat : Animal 19 20 @end 21 22 #import "Cat.h" 23 24 @implementation Cat 25 -(void)run{ 26 27 NSLog(@"猫在爬树,被蜜蜂蜇了!"); 28 29 } 30 @end 31 32 #import "Animal.h" 33 34 @interface Dog : Animal 35 -(void)run; //可以不写 36 -(void)eat; 37 @end 38 39 #import "Dog.h" 40 41 @implementation Dog 42 43 -(void)run{ 44 45 NSLog(@"狗以80码的速度冲出去,没撞树上!"); 46 47 } 48 -(void)eat{ 49 NSLog(@"狗在吃东西"); 50 } 51 @end 52 53 #import "Dog.h" 54 55 @interface BigYellowDog : Dog 56 57 @end 58 59 #import "BigYellowDog.h" 60 61 @implementation BigYellowDog 62 -(void)run{ 63 64 NSLog(@"大黄狗在跑,撞猪身上了"); 65 } 66 @end 67 68 /* 69 多态的概念: 70 71 不同的对象以自己的方式响应父类同名的方法,这就是多态 72 73 体现出来: 74 75 父类的指针指向了子类的对象 76 77 多态的条件: 78 79 1)有继承关系 80 2)有方法重写(子类把父类的同名方法给重写了) 81 82 */ 83 84 85 #import <Foundation/Foundation.h> 86 #import "Dog.h" 87 #import "Animal.h" 88 #import "Cat.h" 89 #import "BigYellowDog.h" 90 int main(int argc, const char * argv[]) 91 { 92 93 @autoreleasepool { 94 //****没有使用多态***** 95 Animal *ani = [Animal new]; 96 [ani run]; 97 98 Dog *d1 = [Dog new]; 99 [d1 run]; 100 101 Cat *cat = [Cat new]; 102 [cat run]; 103 104 //****** 使用多态 ******* 105 //父类指针 指向了子类对象 106 Animal *a2 = [Dog new]; 107 [a2 run]; 108 109 Animal *a3 = [Cat new]; 110 [a3 run]; 111 112 Dog *d2 = [BigYellowDog new]; 113 [d2 run]; 114 115 Animal *ani5 = [BigYellowDog new]; 116 [ani5 run]; 117 118 //*******多态的使用注意***** 119 Animal *an6 = [Dog new]; 120 //an6 Animal类型 121 //编译的时候会报错 122 // [an6 eat]; //报错的 123 //能否执行? [(Dog *)an6 eat]; 把an6强制转换为 Dog类型 124 [(Dog *)an6 eat]; 125 126 Animal *a7 = [Animal new]; 127 // [a7 eat]; //不可以 ,错误的用法 128 //骗编译器 本身还是Animal对象 ,实际上没有这个方法 129 //Dog 类有eat方法, Animal类没有eat方法的 130 [(Dog *)a7 eat]; 131 } 132 return 0; 133 }
第三讲 类的本质
本小节知识点:
1、【了解】类类型的对象
2、【掌握】类的本质
3、【掌握】类对象如何获取
1、类类型的变量(实例变量)
Person *p = [Person new];
//把类的代码加载到代码区
//产生一个类对象,类型是Class isa指向代码区的Person类
//实例化对象三件事
//申请空间 初始化 返回地址
//对象isa 指向类对象
2、类的本质
类的本质其实也是一个对象(类对象)
类对象
类对象在程序运行时一直存在。
类对象是一种数据结构,存储类的基本信息:类大小,类的版本以及消息与函数的映射表等。
类对象所保存的信息在程序编译时确定,在第一次使用该类的时候被加载到内存中。
类对象代表类,class代表类对象,类方法属于类对象。
如果消息的接收者是类名,则类名代表类对象。
运行时,所有类的实例都由类对象生成,类对象会把实例的isa的值修改成自己的地址,每个实例的isa都指向该实例的类对象。
从类对象里可以知道父类信息、可以响应的方法等
类对象只能使用类方法,不能用实例方法。
Person *p = [Person new];
p 实例对象
Person 也是一个对象(类对象),是Class类型
3、类对象如何获取
1)通过实例对象获取
Dog *dog = [Dog new];
Dog *d2 = [Dog new ];
//第一种方法获取类对象
Class c = [dog class];
Class c2 = [d2 class];
2)通过类名获取(类名其实就是类对象)
Class c3 = [Dog class];
第四讲 类对象的使用
本小节知识点:
1、【了解】类对象的用法
1 #import <Foundation/Foundation.h> 3 @interface Person : NSObject 4 -(void)test; 5 +(void)test; 6 @end 8 #import "Person.h" 10 @implementation Person 11 12 -(void)test{ 13 NSLog(@"-test"); 15 } 16 +(void)test{ 18 NSLog(@"+test"); 19 } 20 21 @end 22 23 /* 24 原来使用类名可以做哪些事情? 25 创建对象 26 [Person new]; 27 28 调用类方法 29 [Person test]; //test 是类方法 30 31 Person *p = [Person new ]; 32 Class c1 = [p class]; //Person 33 34 c1---->Person 35 36 类对象的使用: 37 1)创建实例对象 38 Person *p1 = [c1 new]; 39 2)调用类方法 40 [c1 test]; 41 42 */ 43 #import <Foundation/Foundation.h> 44 #import "Person.h" 45 int main(int argc, const char * argv[]) 46 { 48 @autoreleasepool { 49 //获取类对象 50 Class c1 = [Person class]; 51 //c1 ----> Person 52 //使用类对象创建实例对象 53 Person *p = [c1 new]; 54 [p test]; //-test 表示对象创建成功,c1当Person来用的 55 //使用类对象调用类方法 56 [c1 test]; //+test 59 } 60 return 0; 61 }
第五讲 类对象的存储细节
【了解】类对象的存储
1、类对象的存储
第六讲 SEL类型
【了解】SEL类型
1、SEL类型
SEL:全称selector表示方法的存储位置。
方法在内容中是怎么存储的?
Person *p = [[Person alloc] init];
[p test];
寻找方法的过程:
(1)首先把test这个方法名包装成sel类型的数据:
(2)根据SEL数据找到对应的方法地址:
(3)根据方法地址调用相应的方法。
(4)注意:在这个操作过程中有缓存,第一次找的时候是一个一个的找,非常耗性能,之后再用到的时候就直接使用。
关于 _cmd:每个方法的内部都有一个_cmd, 代表着当前方法.
注意:SEL其实是对方法的一种包装,将方法包装成一个SEL类型的数据,去寻找对应的方法地址,找到方法地址后就可以调用方法。这些都是运行时特性,发消息就是发送SEL,然后根据SEL找到地址,调用方法。
SEL s1 = @selector(eat);
//通过s1 去调用了
[p2 performSelector:s1];
1 #import <Foundation/Foundation.h> 2 3 @interface Person : NSObject 4 -(void)test; 5 @end 6 7 #import "Person.h" 8 9 @implementation Person 10 -(void)test{ 11 NSLog(@"-test"); 12 } 13 @end 14 15 #import <Foundation/Foundation.h> 16 #import "Person.h" 17 int main(int argc, const char * argv[]) 18 { 19 20 @autoreleasepool { 21 22 Person *p = [Person new]; 23 [p test]; //跟下面SEL一样 24 25 //手动的把test方法包装成 SEL 类型 26 SEL s1 = @selector(test); 27 //响应方法 28 [p performSelector:s1]; 29 } 30 return 0; 31 }