OC的面向对象的三大特性

2018-10-26  本文已影响0人  波澜不惊的少年

一、封装

1. 面向对象的三大特性:封装(成员变量)、继承和多态

 在OC语言中,使用@interface和@implementation来处理类。

 @interface就好像暴露在外面的时钟表面,像外界提供展示以及接口。@implementation就好像隐藏在时钟内部的构造实现,把具体的实现封装了起来。

2.封装:隐藏内部实现,稳定外部接口.

    封装就是定义类,定义属性,定义方法;

3. Set方法

    在开发过程中,考虑到安全性要求,我们一般不在成员变量名前面使用@public、@protected等关键字修饰,而是使用Set方法来为对象提供成员变量的值。在set方法的        内部也可以对一些不合理的赋值进行筛选过滤。

    Set方法的作用:为外界提供一个设置成员变量值的方法

      命名规范:

      1)方法名必须以set开头;

      2)Set后面跟上成员变量的名称,首字母大写;

      3)返回值一定是void;

      4)一定要接收一个参数,而且参数类型需要和成员变量的类型一致;

      5)形参名不能和成员变量名一样(苹果官方推荐成员变量名前加_以示区分);

      Set方法的好处:(提供set 以及get 给别人使用就行)

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

        2)对设置的数据进行过滤 ; 

代码例子:

#import <Foundation/Foundation.h>

// 声明

@interface Person : NSObject {

    //

    int _age;

}

//

- (void)setAge:(int)age;

- (void)print;

@end

// 实现

@implementation Person

//

- (void)setAge:(int)age {

    _age = age;

}

- (void)print {

    NSLog(@"age = %i", _age);

}

@end

int main(int argc, const char * argv[]) {

    @autoreleasepool {

        // insert code here...

        NSLog(@"Hello, World!");

        Person *p = [[Person new] init];

        [p setAge:80];

        [p print];

    }

    return 0;

}

4. Get方法

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

    命名规范:

     1)一定有返回值,返回值的类型和成员变量的类型一致

     2)方法名和成员变量名一样

     3)不需要接收任何参数

#import <Foundation/Foundation.h>

// 声明

@interface Person : NSObject {

    //

    int _age;

}

//

- (void)setAge:(int)age;

- (void)print;

// get方法

- (int)age;

@end

// 实现

@implementation Person

//

- (void)setAge:(int)age {

    _age = age;

}

- (void)print {

    NSLog(@"age = %i", _age);

}

// get

- (int)age {

    return _age;

}

@end

int main(int argc, const char * argv[]) {

    @autoreleasepool {

        // insert code here...

        NSLog(@"Hello, World!");

        Person *p = [[Person new] init];

        [p setAge:80];

        [p print];

        //

        NSLog(@"利用get方法返回的值是: %i", [p age]);

    }

    return 0;

}

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

    注意2: 成员变量名的命名以下划线开头,get方法名不需要带下划线,使用下划线开头有两个好处:(1)与get方法的方法名区分开来;(2)可以和一些其他的局部变量区分开来,下划线开头的变量,通常都是类的成员变量。

5. Self关键字 (和Android中this关键字的作用类似)

    Self是一个指针,谁调用了当前方法,self就指向谁

  【出现在对象方法中,就代表着当前对象,出现在类方法中,就代表着当前类】

    Self的用途:

      (1) 可以利用self->成员变量名访问当前对象内部的成员变量(仅在对象方法中)

      (2) [self 方法名];可以调用其他的对象方法或者是类方法

  关于self的关键字使用:http://blog.csdn.net/haojie2014/article/details/46908955

6.补充:OC弱语法

注意的是:Oc语言是一门弱语法的语言,编译的时候不会报错,所以这就要求我们开发过程中一定要按照既定的规范进行写代码。

  1. oc在运行过程中才会检测对象有没有实现该相应的方法(动态监测),而即使没有写方法的实现代码,在编译、连接过程中只会显示警告,运行时会崩溃,如果在手机上运行运行遮掩的代码,运行过程中很可能就会造成闪退。

  经典错误:不能识别消息发送给对象(运行时会监测方法有没有实现),会使程序运行时自动崩溃(闪退)

-[Person test]: unrecognized selector sent to instance 0x7f9738403420

  2. 如果对象调用的方法只有声明没有实现,编译能通过(有警告:warning: method definition for ‘test‘ not found [-Wincomplete-implementation]),但是能连接成功,运行时还是会导致程序崩溃

  3. 如果对象调用的方法只有实现,没有声明,编译能通过,能连接成功,也能顺利运行,但是不采用这样的写法

  4. 只有类的声明没有类的实现也可以顺利运行,但是不采用这样的写法

#import <Foundation/Foundation.h>

@interface Person : NSObject {

    int _age;

}

- (void)test;

@end

@implementation Person

// 没有实现test方法

@end

int main(int argc, const char *argv[]) {

    @autoreleasepool {

        Person *p = [Person new];

        [p test];

    }

    return 0;

}

二、 继承

1. 程序的世界与人类的“对象”世界在思想上没有什么区别,子类继承了父类,其实就拥有了父类的方法和属性(成员变量),继承及时代码优化公共部分交给父类。

    子类可以直接复用父类中的成员。子类继承父类所有方法的声明和实现,非私有的实例变量以及协议,继承是要在 .h 文件中声明一下。继承具有单根性和传递性。

拓展:

   Objective-C不支持多继承,这与c#, java一致,但与c++有点区别。也就是说每个类(除了根类NSObjec)外有且只能有一个基类,但是可以有另个或者若干个子类,这种关系正是树的结构特征,所以oc类呈现出的是树形层次的结构。

2. 继承的好处:

    1). 抽取出了重复的代码;

    2). 建立了类和类之间的联系;

    缺点:

    耦合性太强;

3. OC中的继承

@interface Animal:NSObject

//动物里继承了NSObject,获得NSObject类的方法;

@end

@interface Dog :Animal

//dog类继承Animal类

@end

注意:OC语言是单继承语言。在oc语言中,基本上所有类的根类都是NSObject类。

4. 继承的使用注意

  1). 编译器从上往下执行,所以在子类前面至少应该要有父类的声明;

  2). oc中不允许子类和父类拥有相同名称的成员变量名;

  3). oc中的子类可以拥有和父类相同名称的方法,在子类调用时,优先去自己的内部寻找,如果没有则一层一层往上找;

提示:重写就是子类重新实现了父类中的某个方法,覆盖了父类以前的实现。

其实就是创建一个Student *s = [[Student alloc] init];

此时会把Student类和这个类的父类加载紧内存;

提示:每个类中都有一个super class指针,该指针指向自己的父类。对象中有一个isa指针,该指针指向调用该对象的类。

5. 继承与组合

继承的适用场合:

  1)当两个类拥有相同的属性和方法时,就可以将相同的属性和方法抽取到一个父类中。

  2)当A类完全拥有B类中的部分属性和方法时,可以考虑让B类继承A类(考虑),在这种情况下,也可以考虑使用组合。

继承: A 是 B;

组合:A 中有 B; 就是让B这个类作为类A的属性;

6. 关键字Super

  Super关键字,在子类中重写方法时,可以让调用者跳过这一层而调用父类中的方法。

-(void)dealloc {

  //

  [super dealloc];

}

  作用:

   1)直接调用父类的某一个方法;

   2)Super处在对象方法中,那么就会调用父类的对象方法;super处于类方法中,那么就会调用父类的类方法;

使用场景: 子类重写父类方法时,想保留父类的一些行为

三、 多态

1. 多态在代码中的体现,就是多种形态,必须要有继承,没有继承就没有多态;

2. 在使用多态时,会进行动态监测,以调用真实的对象方法;

3. 多态在代码中的体现即父类指针指向子类对象;

4. 不同对象对同一消息的不同相应,子类可以重写父类的方法,多态就是允许方法重名 参数或返回值可以使父类行传入或返回。  

#pragma mark - polymorphism

void polymorphism() {

    // Animal

    Animal *a = [[Animal alloc] init];

    [a eat];

    // Dog

    Dog *d = [[Dog alloc] init];

    [d eat];

    // Guess what output

    // The parent class pointer to the child object

    Animal *a1 = [[Dog alloc] init];

    NSLog(@"这里使用Dog初始化Animal!");

    [a1 eat];

    // 动态监测,调用方法时候会检测对象的真是类型

    // Guess what output again

    // Dog *d1 = [[Animal alloc] init];

    // NSLog(@"这里使用Animal初始化Dog");

    // [d1 eat];

}

5. 多态的局限性:父类类型的指针变量不能直接调用子类特有的方法

Animal *a=[[Dog alloc] init];

[a run]; //在Animal类中没有run方法,这里调用了狗对象的方法。

解决方法:可以将a强制转换为Dog*类型的变量,如下:

Dog *d=(Dog *)a;//使用强制转换,这里a和d指向的是同一个狗对象

6. 总结

  1)没有继承就没有多态;

  2)代码的体现,父类类型的指针指向子类对象;

  3)好处:如果函数方法参数中使用的是父类类型,则可以传入父类和子类对象,而不用再去定义多个函数来和响应的类进行匹配;

  4)局限性:父类类型的变量不能直接访问子类特有的方法,如果一定要调用,则必须强制转化为子类特有的方法;

上一篇 下一篇

猜你喜欢

热点阅读