天天看点

【Objective-C学习笔记】OC三大特性:封装、继承、多态

第一部分 封装 一、封装的作用 1、过滤不合理的值

2、屏蔽内部的赋值过程

3、让外界不必关注内部的细节

二、set方法和get方法 1、使用场合 被@public修饰的成员变量可以在任何位置随意的赋值,这样很不安全,我们应该使用set方法和get方法来管理成员变量的访问。

#import <Foundation/Foundation.h>

@interface Student : NSObject
{
    int _age;   
}

- (void)setAge:(int)age;    //set方法

- (int)age;    //get方法

@end

@implementation Student
// set方法的实现
- (void)setAge:(int)age
{
    // 对传进来的参数进行过滤
    if (age <= 0)
    {
        age = 1;
    }
    
    _age = age;
}
// get方法的实现
- (int)age
{
    return _age;
}

@end

int main()
{
    Student *stu = [Student new];
    
    [stu setAge:-10];
    
    NSLog(@"学生的年龄是%d岁", [stu age]);
  
    return 0;
}
// 学生的年龄是1岁,因为在set方法中,会对传入的参数过滤,-10岁这样的年龄不合理。
           

2、成员变量的命名规范 (1)一定要以下划线 _ 开头

(2)作用:

1> 让成员变量和get方法的名称区分开

2> 可以跟局部变量区分开,一看到下划线开头的变量,一般都是成员变量

3、set方法 (1)作用:提供一个方法给外界设置成员属性值,可以在方法里面对参数进行相应过滤

(2)命名规范:

1> 方法名必须以set开头

2> set后面跟上成员变量的名称,成员变量的首字母必须大写

3> 返回值一定是void

4> 一定要接收一个参数,而且参数类型跟成员变量类型一致

5> 形参的名称不能跟成员变量名一样

4、get方法 (1)作用:返回对象内部的成员变量

(2)命名规范:

1> 肯定有返回值,返回值类型肯定与成员变量类型一致

2> 方法名跟成员变量名一样

3> 不需要接收任何参数

三、类方法

#import <Foundation/Foundation.h>

@interface Person : NSObject
{
    int age;
}

// 类方法是以+开头
- (void)test;
+ (void)test;
@end

@implementation Person

- (void)test
{
    NSLog(@"111");
}

+ (void)test
{
    NSLog(@"333");    //不能访问成员变量
}

@end

int main()
{
    Person *p = [Person new];
    [p test];    //对象方法调用

    [Person test];    //类方法调用
    
    return 0;
}
           

1、类方法的命名规范 (1)加号 + 开头

(2)方法只能由类(名)调用

(3)类方法中不能访问实例变量(成员变量)

2、与对象方法的区别以及优点 (1)对象方法

1> 减号 - 开头

2> 只能由对象来调用

3> 对象方法中能访问当前对象的实例变量(成员变量)

(2)优点 1> 不依赖于对象,执行效率高

2> 能用类方法尽量用类方法

3> 类方法和对象方法的名字可以相同 3、使用场合 当方法内部不需要使用到成员变量时,就可以改为类方法

四、self关键字 1、self是指针,指向当前方法的调用者 2、self的用途

(1)谁调用了当前方法,self就代表谁

1> self出现在对象方法中,self就代表对象

2> self出现在类方法中,self就代表类

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

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

1> 如果在对象方法中,可以调用类方法

2> 如果在类方法中,一定不能调用对象方法 第二部分 继承 一、继承的格式以及优点

#import <Foundation/Foundation.h>

/******** Animal的声明 ********/
@interface Animal : NSObject
{
    int _age;
}

- (void)setAge:(int)age;
- (int)age;
@end

/******** Animal的实现 ********/
@implementation Animal
- (void)setAge:(int)age
{
    _age = age;
}
- (int)age
{
    return _age;
}
@end

/******** Dog ********/
@interface Dog : Animal    //Dog是子类,Animal是父类,子类继承父类
@end

@implementation Dog
@end

int main()
{
    Dog *d = [Dog new];
    
    [d setAge:10];
    
    NSLog(@"age=%d", [d age]);
    
    return 0;
}
           

1、继承的基本使用 (1)子类方法和属性的访问过程:如果子类没有,就去访问父类的 (2)虽然被继承了,但是父类中的实例变量和方法还是能继续使用 2、继承的好处:

(1)抽取重复代码

(2)建立了类之间的关系,Dog是Animal的子类,Animal是Dog的父类。

(3)子类可以使用父类中的所有成员变量和方法,Dog : Animal,继承了Animal,相当于拥有了Animal里面的所有成员变量和方法。

3、继承的细节: (1)基本上所有类的根类是NSObject

(2)不允许子类和父类拥有相同名称的成员变量 4、重写: (1)子类重新实现父类中的某个方法,覆盖父类以前的做法 (2)注意点 1> 父类必须声明在子类的前面,不用管父类的实现。

2> 调用某个方法时,优先去当前类中找,如果找不到,就去父类中找。

(3)super关键字 1> 使用场合:在子类方法中,想直接调用父类方法 2> 注意:super处在对象方法中,那么就会调用父类的对象方法;super处在类方法中,那么就会调用父类的类方法

5、继承的使用场合 (1)当B类是A类的时候,就让B类继承A类

@interface Person : NSObject    //A类:人
@end

@interface Student : Person    //B类:学生
@end
           

(2)当B类拥有A类的时候,就写成组合

@interface Car : : NSObject    //A类:车
{
    int _speed;    //速度
    int _wheels;    //轮子
}
@end

@interface Person : NSObject    //B类:人
{
    Car *_car;    // 人拥有车
    int _age;    //年龄
}
@end
           

第三部分 多态 一、多态的基本使用

#import <Foundation/Foundation.h>
@interface Animal : NSObject
- (void)eat;
@end

@implementation Animal
- (void)eat
{
    NSLog(@"Animal-eat!");
}
@end

@interface Dog : Animal
@end

@implementation Dog
- (void)eat
{
    NSLog(@"Dog-eat!");
}
@end

int main()
{
    Dog *d = [Dog new];
    // 多种形态
    Animal *a = [Dog new];
    [a eat];    // Dog-eat!
    return 0;
}
           

1、子类对象赋值给父类指针 2、调用方法时,会检测对象的真实形象,在运行时根据对象的类型确定动态调用的方法。虽然指针是父类,但是对象实际是子类,那么会去子类里面找eat方法

二、多态的好处

void feed (Animal *aa)
{
    [a eat];
}

Animal *a = [Animal new];
feed(a);    //Animal-eat!

Dog *d = [Dog new];
feed(d);    //Dog-eat!
           

1、如果参数中使用的是父类类型,可以传入父类、子类对象,节省代码 2、传入以后,会检测对象的真实形象,然后执行方法

三、多态的局限性 1、父类类型指针变量不能直接调用子类对象中特有的方法

// 狗类特有的方法
- (void)run
{
    NSLog(@"Dog-run!");
}

Animal *a = [Dog new];
// 编译器会警告Animal类中没有run这个方法
// [a run];
           

2、把父类强转成子类,才可以调用。

// 将a转为Dog *类型的变量
Dog *dd = (Dog *)a;
    
[dd run];