黑马程序员——OC语言基础篇---面向对象之三大特性

------Java培训、Android培训、iOS培训、.Net培训 期待与您交流! -------

本篇主要是讲面向对象的三大特性:封装、继承和多态。

一、 封装

前篇在说到访问成员变量的时候不要使用public,那么为了保证成员变量的封装性,引入了set方法(setter)和get方法(getter),setter是用来设置成员变量的值,而getter是用来取成员变量的值。

1.set方法

oc中提供一个方法给外界设置成员变量的属性值,这样叫set方法
有命名规范
1 方法名必须以set开头
2 set后面跟上成员变量的名称,成员变量的首字母必须大写
3 返回值一定是void,一定要接受一个参数,参数类型与成员变量类型一致
4 形参的名称不能与成员变量名一样

2.get方法

1) 作用:返回对象内部的成员变量
2) 命名规范:get方法的名称一般就跟成员变量同名
通过一个简单的例子来看一下,setter和getter的使用方法和好处吧
#import 
@interface Student:NSObject
{
    //@public
    int age;
}
//提供方法给外界设置age属性值
//set方法
- (void)setAge:(int) stuage;
//返回对象内部的成员变量
//get 方法
- (int)age;
- (void)study;
@end
@implementation Student
- (void)setAge:(int) stuage
{
    if (stuage <= 0)
    {
        stuage = 1;
    }
    age = stuage;
}
- (int)age
{
    return age;
}
- (void)study
{
    
    NSLog(@"%d岁的学生在学习",age);
}
@end
int main()
{
    Student *s = [Student new];
    //s->age = 25;
    [s setAge:20];
    //[s study];
    NSLog(@"学生的年龄是%d岁",[s age]);
    [s study];
    
    return 0;
}

上面的@public已经被注释掉了,现在的成员变量是protected,也就是在main函数中没有办法通过变量名直接访问了。但是,提供了set方法和get方法,对于main函数来说,只要能够赋值和取值就可以了,并不关心类内部的成员变量,那么只需要提供方法就足够了。这样保障了类内部的封装性和安全性,成员变量是不能随便访问和修改的,同时,在set方法中可以过滤输入的值,保障输入数据的有效性。还有一点,那就是关于只读,有的变量只可以访问它的值,而不能进行修改,这时候,我们只提供getter就可以了。这就是面向对象编程思想了。

二、继承

继承其实我们已经用到了,上面代码在声明类的时候用到了 :NSObject ,这就是继承,Student可以称为子类(subclass\subclasses),NSObject是它的父类(superclass)。
在前篇我们讲到new方法的时候曾提供,子类可以调用父类的方法,还可以对父类的方法进行方法重写,也可以扩充写自己特有的方法。
下面将通过一段代码来讲述一下:继承、类方法和super关键字
#import 
@interface Zoombie : NSObject
- (void)walk;
- (void)test;
+ (void)test;
@end
@implementation Zoombie
- (void)walk
{
    NSLog(@"僵尸往前挪两步");
}
- (void)test
{
    NSLog(@"这里是test对象方法");
}
+ (void)test
{
    NSLog(@"这里是test类方法");
}
@end
@interface JumpZoombie : Zoombie
- (void)walk;
+ (void)test;
@end
@implementation JumpZoombie
- (void)walk
{
    
    NSLog(@"僵尸往前跳两下");
    [super walk];
}
+ (void)test
{
    [super test];
}
@end
int main()
{
    JumpZoombie *jz = [JumpZoombie new];
    [jz walk];
    [JumpZoombie test];
    [jz test];
    return 0;
}
运行结果:

2015-04-15 14:34:46.879 a.out[2921:507] 僵尸往前跳两下

2015-04-15 14:34:46.881 a.out[2921:507] 僵尸往前挪两步

2015-04-15 14:34:46.881 a.out[2921:507] 这里是test类方法

2015-04-15 14:34:46.882 a.out[2921:507] 这里是test对象方法


JumpZoombie继承了Zoombie类,它就又有了 Zoombie的成员变量和方法。
(1)我们先来看[jz walk]; 
JumpZoombie对父类的walk方法进行了重写,增加了一部分内容又通过super关键字,调用了父类的方法,所以我们知道,在子类中要想调用父类的方法可以使用super关键字。
(2)[JumpZoombie test];
这一句调用的是JumpZoombie中声明的 + (void)test 方法,这是一个类方法,类方法是以 + 开头的
类方法和对象方法对比
1) 对象方法
➢ 以减号-开头
➢ 只能让对象调用,没有对象,这个方法根本不可能被执行
➢ 对象方法能访问实例变量(成员变量)
2) 类方法
➢ 以加号+开头
➢ 只能用类名调用,对象不能调用
➢ 类方法中不能访问实例变量(成员变量)
➢ 使用场合:当不需要访问成员变量的时候,尽量用类方法
3) 类方法和对象方法可以同名
关于二者之间相互调用的问题,一般是可以用对象方法调用类方法。但是用类方法调用对象方法其实也是可以的,要这样调用必须先有一个实例化对象。
(3)[jz test];
要注意,JumpZoombie没有test这个对象方法,但是它可以调用的原因是它继承了Zoombie类,它里面有- (void)test方法。这表明子类可以继承父类的方法。

总结

※继承的好处
  抽取重复代码
  建立了类之间的关系
 子类可以拥有父类的成员变量和方法
※继承的坏处:耦合性强(两个类之间的关系)

OC中不允许子类和父类拥有相同名称的成员变量
但是方法允许同名,这就是方法重写
重写:子类重新实现父类中的某个方法,覆盖父类以前的方法
父类必须声明在子类之前,实现随便
调用某个对象的方法时优先去子类中寻找,如果没有回去父类中寻找

三、多态

有继承才会有多态,多态实际上就是用父类指针指向子类对象
#import 
@interface Animal : NSObject
- (void)eat;
@end
@implementation Animal
- (void)eat
{
    NSLog(@"Animal吃东西----");
}
@end
/*********Dog 类***********/
@interface Dog : Animal
- (void)eat;
- (void)run;
@end
@implementation Dog
- (void)eat
{
    NSLog(@"Dog吃东西----");
}
- (void)run
{
    NSLog(@"Dog跑起来");
}
@end
/*********Cat 类***********/
@interface Cat : Animal
- (void)eat;
@end
@implementation Cat
- (void)eat
{
    NSLog(@"Cat吃东西----");
}
@end

//函数:喂动物
void feed(Animal *d)
{
    [d eat];
}

int main()
{
    Animal *dd = [Dog new];
    feed(dd);
    [dd run];
    
    Animal *cc= [Cat new];
    feed(cc);
    
    NSString *s = [Cat new];
    [s eat];
    return 0;
}
Animal *dd = [Dog new];虽然指针是Animal,但是,实际上得对象是Dog,调用方法时会检测对象的真实形象
多态的好处
如果函数参数使用的时父类类型,子类的对象也可以传进来,节省代码,上述代码中的feed()函数就是此类应用
多态的局限性
不能直接用父类指针调用子类特有的方法
如果用父类指针调用了子类特有的方法,会报一个经典错误:

unrecognized selector sent to instance

给对送了一个不可别的消息

这是因为找不到对应的方法,但是编译链接的时候并不会报错,这是OC的弱语法导致的。

弱语法

有方法未实现,而调用了方法,程序编译时只会有警告,链接时不会报错,只在程序运行时出错
而如果方法有实现,而未声明,程序是可以运行的
但是,标准写法就是声明和实现都必须有

self关键字

self一般在方法实现时使用,它实际上是一个指针,指向的是当前的对象,可能是类,也可能是由类创建的对象
#import 
@interface Dog:NSObject
- (void)bark;
- (void)run;
@end
@implementation Dog
- (void)bark
{
    NSLog(@"汪汪汪");
}
- (void)run
{
    [self bark];
    NSLog(@"跑跑跑");
}
@end
int main()
{
    Dog *d = [Dog new];
    [d run];
    return 0;
}
[self bark];这里的self指向的就是Dog对象 d。

你可能感兴趣的:(黑马程序员——OC语言基础篇---面向对象之三大特性)