黑马程序员——OC语言学习——OC面向对象的三大特性:封装、继承、多态,OC字符串——NSString

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

一、   封装                                                                                  

在之前我们操作对象里的成员变量时候,需要在定义类时,在类的声明里加上 @public

如:

@interface Student : NSObject
{
    @public
    int age;
    int no;
}

可以用指向对象的指针直接操作对象内部的数据,而面向对象思想处理问题时,是要将内部结构不要直接暴露给外界。

这就有了封装的思想

封装:将设置成员变量分装到一个方法中去

好处:

 1.让外界不能直接访问,修改成员变量值,保证了,成员变量的安全性

 2.隐藏一些内部细节,不让外界知道,比如赋值操作

执行封装的方法有set方法和get方法

1、   set方法

如:

@interface Student : NSObject
{
    int age;
    int no;    
}
/ /set方法的声明
- (void)setAge:(int)newAge;
@end

@implementation Student

// set方法的实现
- (void)setAge:(int)newAge   // 提供一个方法给外界设置
{
    if (newAge <= 0) {              //对传递进来的参数进行过滤
        newAge = 1;
    }
    age = newAge;
}
@end


 1. set 方法的作用:提供一个方法给外界设置age 属性值

  2. set 方法的命名规范

    1> 方法名必须以set开头

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

    3> 返回值一定是void

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

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


2、   get方法

如:

@interface Student : NSObject
{
    int age;
    int no;
}

//get方法声明
- (int)age;
@end

@implementation Student

//get方法实现
- (int)age
{
    return age;        // 返回 成员变量age
@end


 1.get方法的作用:返回对象内部的成员变量

 2.get方法的命名规则:

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

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

    3>  不需要接受任何参数


当成员变量只读的时候,可不提set方法


3、  成员变量的命名规范

        一定要以下划线 _ 开头

    好处

     1.让get方法名和成员变量名区分开来

     2.让成员变量和局部变量区分开来。 一看到 _开头,一般都是成员变量

如:

#import

typedef enum{        
    Sexman,
    Sexwomen
} Sex;


@interface Student : NSObject
{// 成员变量的命名规范:一定要以下划线 _ 开头
    /*
     好处
     1.让get方法名和成员变量名区分开来
     2.让成员变量和局部变量区分开来
     一看到 _ 开头,一般都是成员变量
     */
    int _no;
    Sex _sex;
}

// sex 的set和get方法
- (void)setSex: (Sex)sex;
- (Sex)sex;

// no 的set方法和get方法
- (void)setNo: (int)no;
- (int)no;
@end

@implementation Student
// sex 的set和get方法的实现
- (void)setSex: (Sex)sex
{
    _sex = sex;
}
- (Sex)sex
{
    return _sex;
}

// no 的set方法和get方法的实现
- (void)setNo: (int)no
{
    _no = no;
}
- (int)no
{
    return _no;
}

@end

int main()
{
    Student *stu = [Student new];
    
    [stu setSex: Sexwomen];
    [stu setNo: 23];
    
    NSLog(@"学生的学号:%d", [stu no]);
    NSLog(@"学生的性别:%d", [stu sex]);
}

二、   类方法

1、   类方法和对象方法的比较

对象方法

 1> 减号开头 - 开头

 2> 只能有对象来调用(指向对象的指针)

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

 类方法

 1>  加号 + 开头

 2>  只能由类(名)来调用

 3>  类方法中不能有成员变量(实例变量),即不能访问成员变量,因为这时还没有创建对象

 

     可以允许类方法和对象方法同名

 

 类方法的的好处和使用场合

 1> 不依赖于对象,执行效率高,因为直接调用类名进行操作

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

 3> 场合: 当方法内部不需要使用成员变量时,即可用类方法

2、   典型错误案例

1. 类名调用了对象方法

@interface Person : NSObject
//类方法:打印类名
+ (void)printClassName;
- (void)test;
@end

@implementation Person
+ (void)printClassName
{
    NSLog(@"这个类名是Person");
}

- (void)test
{
    NSLog(@"调用了test函数");
}
@end

int main()
{
    Person *p = [Person new];
    // 类调用了对象的方法
    [Person test];
    /*
    错误信息 : 
    warning: class method '+test' not found    这个类方法没有被找到
    +[Person test]: unrecognized selector sent to class 一个无法识别的消息传递给了对象
     */
    return 0;
}



2. 对象指针调用了类方法

@interface Person : NSObject
//类方法:打印类名
+ (void)printClassName;
- (void)test;
@end

@implementation Person
+ (void)printClassName
{
    NSLog(@"这个类名是Person");
}

- (void)test
{
    NSLog(@"调用了test函数");
}
@end

int main()
{
    Person *p = [Person new];
    //  对象指针调用了类方法
    [p printClassName];
    /*
    错误信息 : 
     warning: instance method '-printClassName' not found    这个对象方法没有被找到
    -[Person printClassName]: unrecognized selector sent to instance 
     一个无法识别的消息传递给了对象
     */
    return 0;
}

3. 对象指针调用了未存在的对象方法,类名调用了未存在的类方法       也会出现如上错误


三、   self关键字

self 的用途: 谁调用了当前方法,self就代表谁

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

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

 1> 概念:指向了当前对象(方法调用者)

 2> 在对象方法中,可以用“self—>成员变量” 访问当前对象内部的成员变量

#import

@interface Person : NSObject
{
    int _age;
}

- (void)setAge: (int)age;
- (int)age;
- (void)test;
@end
@implementation Person
- (void)setAge: (int)age
{
    //等价表达:self->_age = age;
    _age = age;
}
- (int)age
{
    return _age;
}
- (void)test
{
   //self (本质为指针)指向方法调用者,代表当前对象这里的方法调用者为对象,
    int _age = 20;
    
    NSLog(@"Person的年龄是%d岁", self->_age);
}

@end

int main()
{
    Person *p = [Person new];
    [p setAge:10];
    [p test];
    
    
    return 0 ;
}

 3> [self 方法名]; 在对象的方法中调用当前对象的方法  在类的方法中调用当前类的方法 

#import 

@interface Dog : NSObject
- (void)bark;
- (void)run;
+ (void)test1;
+ (void)test2;
@end

@implementation Dog
// 对象方法
- (void)bark
{
    NSLog(@"汪汪汪");
}
- (void)run
{
    [self bark];     // 此时self代表对象本身,则 调用的对象方法 bark
    //NSLog(@"汪汪汪");
    NSLog(@"跑跑跑");
}

// 类方法
+ (void)test1
{
    NSLog(@"类方法调用了test1");
}
+ (void)test2
{
    [self test1];   // 此时self代表Dog类,则 调用的类方法 test1
}
@end
self使用注意:方法内调用方法本身,会陷入死循环

#import 

@interface Dog : NSObject
- (void)bark;
+ (void)test1;
@end

@implementation Dog
// 对象方法
- (void)bark
{
    [self bark];  // 方法内用self调用方法本身,会陷入死循环
    NSLog(@"汪汪汪");
}

// 类方法
+ (void)test1
{
    [self test1]; // 方法内用self调用方法本身,会陷入死循环
    NSLog(@"类方法调用了test1");
}
@end


四、   继承

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

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

- (void)setWeight:(double)weight;
- (double)weight;
@end

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

- (void)setWeight:(double)weight
{
    _weight = weight;
}
- (double)weight
{
    return _weight;
}
@end

/********Dog*******/
// : Animal 继承了Animal,相当于拥有了Animal里面的所有成员变量和方法
// Animal称为Dog的父类
// Dog称为Animal的子类
@interface Dog : Animal
@end

@implementation Dog
@end

1、 继承的好处

 1> 抽取重复代码

 2> 建立了类之间的关系

 3> 子类可以拥有父类中的所有成员变量和方法

2、 注意点

  1> 基本上所有类的根类是NSObject

 2> 继承的坏处:耦合性太强

3、 重写

      子类重新实现父类中的某个方法,覆盖父类以前的做法

          注意点:

                 1> 父类必须声明在子类的前面

                 2> 子类不能拥有和父类相同的成员变量

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

4、   继承的使用场合

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

 2> 当A类完全拥有B类中的部分属性和方法时,可以考虑让B类继承A类

 A

 {

       int _age;

       int _no;

 }

 

 B : A

 {

       int _weight;

 }

 

 // 继承:xx 是 xxx

 // 组合:xxx 拥有 xxx

 

5、   组合的使用场合

 A

 {

        int _age;

        int _no;

 }

 

 B

 {

        A *_a;

        int _weight;

 }

@interface Score : NSObject
{
    int _cScore;
    int _ocScore;
}
@end

@implementation Score
@end

@interface Student : NSObject
{
    // 组合
    Score *_score;   //  用组合的方法代替下面两行定义的成员变量
//    int _cScore;
//    int _ocScore;
    int _age;
}
@end

6、关键字super的作用

  1.直接调用父类中的某个方法

  2.super处在对象方法中,那么就会调用父类的对象方法

     super处在类方法中,那么就会调用父类的类方法

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

/***************僵尸********************/
@interface Zoombie : NSObject
- (void)walk;

+ (void)test;
- (void)test;

@end

@implementation Zoombie
- (void)walk
{
    NSLog(@"往前挪两步******");
}

+ (void)test
{
    NSLog(@"Zoombie+test");
}

- (void)test
{
    NSLog(@"Zoombie-test");
}
@end

/**************** 跳跃僵尸 ***************/
@interface JumpZoombie : Zoombie
+ (void)ceShi;
- (void)ceShi;
@end


@implementation JumpZoombie

+ (void)ceShi
{
    [super test];  // 调用父类Zoombie的类方法  test
}

- (void)ceShi
{
    [super test];  // 调用父类Zoombie的对象方法  test
}

- (void)walk
{
    // 跳两下
    NSLog(@"跳两下");
    
    // 直接调用父类的walk方法,代替下面的NSLog(@"往前挪两步----");
    [super walk];
    //NSLog(@"往前挪两步----");
    
}
@end


五、   多态

多态:父类指针指向子类对象


 1.没有继承就没有多态

 2.代码的体现:父类类型的指针指向子类对象

 3.好处:如果函数\方法参数中使用的是父类类型,可以传入父类、子类对象

// 如果参数中使用的是父类类型,可以传入父类、子类对象
void feed(Animal *a)
{
        [a eat];
}

 4.局限性:

 父类类型的变量 不能 直接调用子类特有的方法。否则会有警告

 必须强转为子类类型变量后,才能直接调用子类特有的方法

#import 
/**************** 动物 ***************/
@interface Animal : NSObject
- (void)eat;
@end

@implementation Animal
- (void)eat
{
    NSLog(@"Animal-吃东西----");
}
@end

/**************** 狗 ***************/
@interface Dog : Animal
- (void)run;
@end

@implementation  Dog
- (void)run
{
    NSLog(@"Dog---跑起来");
}
- (void)eat         // 子类Dog重写了 父类方法 eat
{
    NSLog(@"Dog-吃东西----");
}
@end

// 如果参数中使用的是父类类型,可以传入父类、子类对象
void feed(Animal *a)
{
    [a eat];
}

int main()
{
    /*
     用任意类的类型来定义的变量,都能存储对象,并可以用这个指向该对象的变量,来发送消息,执行该对象的方法
     但会生成警告
     */
    NSString *d = [Dog new];// incompatible pointer types initializing 'NSString *' with an  expression of type 'Dog *'
    [d eat]; // class method 'new' is assumed to return an instance of its receiver type('Dog *')
    
    
     Animal *aa = [Dog new];
     // 多态的局限性:父类类型的变量 不能 用来调用子类的方法,否则会有警告
     //[aa run];   // 调用方法时会检测对象的真实形象
     
     // 将aa转为Dog *类型的变量
     Dog *dd = (Dog *)aa;
     [dd run];
    
    /*
     // 多种形态
     //Dog *d = [Dog new]; // Dog类型
     
     // 多态:父类指针指向子类对象
     Animal *a = [Dog new];
     
     // 调用方法时会检测对象的真实形象
     [a eat];
     */
    return 0;
}


六、  OC字符串-NSString 


OC中的字符串是以对象的方式来进行存储的。

OC字符串和C语言字符串对比

如:

/*

    // 最简单的创建字符串的方式

    NSString *str = @"itcast";

    char *name = "itcast";

        

    NSLog(@"我在%@上课", str);

    NSLog(@"%s", name);

*/


OC计算字符串中字符个数的函数——length

如:

    NSString *nameOC =@"哈哈jack";

    char *nameC = "哈哈jack";

    int sizeOC = [name length];   // length方法算的是字数

    int sizeC = strlen(nameC);    //strlen函数算的是字符数

    NSLog(@"sizeOC = %d",sizeOC);  // sizeOC =6

    NSLog(@"sizeC = %d",sizeC);    // sizeC =8


与C语言计算字符串长度函数不同,C语言中strlen函数计算的是字符串长度


创建OC字符串的另一种方式:将变量和字符串整合在一起

     格式:[NSString stringWithFormat:@"字符串+占位符", 变量]

        int age = 23;

        int no = 10;

        char *name = 'jack';

    NSString *newStr = [NSString stringWithFormat:@"My age is %d and no is %d and name is %@", age, no, name];



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

你可能感兴趣的:(IOS学习)