黑马程序员-IOS-OC基础-面向对象语法一

--------------------------------------  android培训 java培训 、ios培训期待与您交流! ---------------------------------

面向对象的思想

1,OC语言是面向对象的,C语言是面向过程的。面向对象和面向过程只是解决问题的两种不同的思想。其实面向对象的思想就是指挥对象做事情,你自己不需要知道知道过程,只要知道结果就行了。 两者的区别:面向过程关注的是解决问题需要哪些步骤;面向对象关注的是解决问题需要哪些对象。
2,常用的术语:
面向过程 Procedure Oriented
面向对象 Object Oriented 简称 OO
面向对象编程 Object Oriented Programming 简称 OOP

类和对象

在面向对象中有两个非常重要的概念:类和对象(类就像图纸,对象就像是根据图纸创建出来的实物。)
1,类的设计
<1>,类名的第一个字母必须是大写。
<2>,类名中不能有下划线。
<3>,类名由多个英文单词组成时,要用驼峰标识。
2,类的声明与实现( 可以声明和定义多个类)
黑马程序员-IOS-OC基础-面向对象语法一_第1张图片
@interface就像暴露在外面的时钟表面;@implementation就好像隐藏在时钟内部的构造实现。
没有@interface,只有@implemetation也可以开发一个类(但不常用)。
<1>,类的声明用关键字@interface 类名 : NSObject { 声明类的成员变量;} @end
<2>,类的实现用关键字@implemetation 类名 @end
<3>,常见错误
1,只有类的声明,没有类的实现。
2,漏掉了@end
3,@interface和@implementation嵌套。
4,两个类的声明嵌套。
5,成员变量没有写在大括号里面。
6,方法的声明写在了大括号内。
<4>,语法细节
1,成员变量不能在{ }中初始不能被外面直接拿去访问。
2,方法不能当做函数一样调用。
3,成员变量\方法不能用static等关键字修饰。
4,类的实现可以写在main函数的后面,只要在类的声明后面就行。
<5>,OC方法和函数的区别
1,OC方法只能声明在@interface和@end之间,只能实现在@implementation和@end之间,也就是说OC的方法不能离开类独立存在。
2,C函数不属于类,跟类没有联系,C函数只归定义函数的文件所有。也就是函数的等级比OC方法的等级高。
3,C函数不能访问OC对象的成员。
4, 低级错误:方法有声明,但是实现的时候写成了函数。
<6>,OC的方法注意
1,方法只有声明,没有实现(经典错误)。
2,方法没有声明,只有实现(编译器会警告,但是能调用,这是OC的弱语法)。
3,编译的时候:访问没有的成员变量直接报错,访问没有的方法,只是警告。
3,方法
<1>不带参数的方法
黑马程序员-IOS-OC基础-面向对象语法一_第2张图片不带参数方法的调用
黑马程序员-IOS-OC基础-面向对象语法一_第3张图片
<2>,带参数的方法
黑马程序员-IOS-OC基础-面向对象语法一_第4张图片
带参数的方法的调用
黑马程序员-IOS-OC基础-面向对象语法一_第5张图片
<3>,多参数方法
黑马程序员-IOS-OC基础-面向对象语法一_第6张图片
多参数的方法的调用
黑马程序员-IOS-OC基础-面向对象语法一_第7张图片
<4>,方法名注意点
(1),冒号:也是方法名的一部分。
(2),同一类中不允许两个对象方法同名。
3, 创建对象    [类名 new];   匿名对象调用方法:[ [Person new] eat ]
练习
/*
 类名:人(Person)
 属性:名字、年龄
 行为:吃饭
 */
//导入Foundation框架的头文件
#import 
//声明Preson类
// : NSObjet 的目的是:让Person这个类具备创建对象的能力(new方法)
@interface Person : NSObject
{
    //声明类的属性(成员变量),成员变量的值默认初始化为0
    @public//@public可以让成员变量被外界访问
    //成员变量尽量以下划线_开头。
    NSString *_name;//名字 默认初始化值为空(nil)  NSString 是OC字符串
    int _age;   //年龄 默认初始化值为0
}
//声明方法(行为)只要是OC对象的方法,必须以减号-开头
- (void)eat;
@end    //类的声明结束

//类的实现
@implementation Person
//实现方法(说清楚方法里面有什么代码)
- (void) eat
{
    NSLog(@"名字叫%@,年龄为%d的人在吃饭",_name,_age);
}
@end    //类的实现结束

//主函数
int main()
{
    //在OC中,想执行一些行为,就写上一个中括号[行为执行者 行为名称]
    //利用类创建对象
    //执行了Person这个类的new行为来创建对象
     Person *p = [Person new];//[Person new]每次都会创建出新的对象,并且返回对象的地址,那么就应该用一个指针变量来保存对象的地址。
    //设置Person对象的属性值
    p -> _name = @"张三";//这里的@代表的是OC字符串
    p -> _age = 25;
    //给p所指向的对象发送一条eat消息,也就是调用Person对象的eat方法。
    [p eat];
    return 0;
    //运行结果是:名字叫张三,年龄为25的人在吃饭
}

面向对象的三大特性

面向对象的三大特性:封装、继承、多态
1,封装
<1>封装的好处:
1,过滤不合理的值。2,屏蔽内部的赋值过程。3,让外界不必关注内部的细节。
//封装
#import 

@interface Student : NSObject
{
    /*
     成员变量得到命名规范:一定要以下划线 _开头
     作用是:
     1,让成员变量和get方法的名称区分开;
     2,可以跟局部变量区分开,
     */
    //@public   //成员变量尽量不要用@public
    int _age;

}
/*set方法
 1,作用:提供一个方法给外界设置成员变量值
 2.命名规范:
 1>,方法名必须以set开头
 2>,set后面跟上成员变量的名称,成员变量的字母必须大写(setAge)
 3>,返回值一定是void
 4>,一定要接收一个参数,而且参数类型跟成员变量类型一致
 5>,形参的名称不能跟成员变量名一样
 */
//声明set方法
- (void)setAge:(int)age;
/*
 get方法
 1,作用:返回对象内部的成员变量。
 2,命名规范:
 1>,肯定有返回值,返回值类型与成员变量类型一致
 2>,方法名跟成员变量名一致
 3>,不需要接收任何参数
 */
//声明get方法
- (int)age;
//声明study方法
- (void)study;
@end

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

    NSLog(@"%d岁的学生在学习",_age);
}
@end

int main()
{
    //创建Student类对象
    Student *stu = [Student new];
    //stu ->_age = 10; //成员变量加@public才可以这样做,但是尽量不要这样。
    [stu setAge:25];
    [stu study];
    NSLog(@"学生的年龄%d",[stu age]);
    return 0;
}
练习
#import 

@interface Dog : NSObject
{
    //定义成员变量
    double _weight;
    double _speed;

}
//声明成员变量的set和get方法
- (void)setWeight:(double)weight;
- (double)weight;

- (void)setSpeed:(double)speed;
- (double)speed;
//声明eat和run方法
- (void)eat;
- (void)run;
@end

@implementation Dog
//成员变量的set方法的实现
- (void)setWeight:(double)weight
{
    _weight = weight;
}
//成员变量get方法的实现
- (double)weight
{

    return _weight;
}
//成员变量的set方法的实现
- (void)setSpeed:(double)speed
{

    _speed = speed;
    
}
//成员变量get方法的实现
- (double)speed
{
    return _speed;
}
//实现eat方法
- (void)eat
{
    NSLog(@"体重为%0.1fKg的狗在吃东西",_weight);
}
//实现run方法
- (void)run
{
    NSLog(@"速度为%0.1fkm/h的狗跑起来了",_speed);
}

@end

//定义主函数
int main()
{
    //创建Dog类对象
    Dog *d = [Dog new];
    //调用set方法
    [d setWeight:20];
    [d setSpeed:30];
    //调用eat方法
    [d eat];
    //调用run方法
    [d run];
    
    return 0;
}

<2>OC弱语法
OC的编译器容错能力比较强,这就说明OC是弱语法,OC是在运行程序的过程中才会去检测对象有没有实现相应的方法,编译期间是不会检测的。
#import 

// 尽管编译器容错能力比较,但是写代码必须规范
@interface Person : NSObject
- (void)test;
@end

@implementation Person
//- (void)test
//{
//    NSLog(@"哈哈哈");
//}
@end

// 一旦运行过程中出错,就会闪退

/*
 -[Person test]: unrecognized selector sent to instance 0x7fd2ea4097c0
 给Person对象发送了一个不能识别的消息:test
 */

int main()
{
    Person *p = [Person new];
    // OC是在运行过程中才会检测对象有没有实现相应的方法
    [p test];
    return 0;
}

2,类方法
<1>基本概念:直接可以用类名来执行的方法(类本身会在内存中占据存储空间,里面有类\对象方法列表)。
<2>类方法和对象方法的对比
#1对象方法:以减号-开头;只能让对象调用,没有对象,这个方法就根本不可能被执行;对象方法能访问实例变量(成员变量)。
#2,类方法:以加号+开头;只能用类名调用,对象不能调用;类方法中不能访问实例变量(成员变量);
#3,适用场合:当不需要访问成员变量的时候,尽量用类方法。
#4,类方法和对象方法可以同名。
//	设计一个方法输出类名
#import 

@interface Person : NSObject
{
    int _age;
}
//声明类方法
+ (void)printClassName;

@end
@implementation Person
//实现类方法
+ (void)printClassName
{
    NSLog(@"这个类的名字是Person");
}

@end

int main()
{
    //调用类方法
    [Person printClassName];

    return 0;
}
3,self关键字
self是指针,代表着谁调用它,它就指向谁。
<1>当成员变量和局部变量同名时,采取就近原则,访问的是局部变量,用self可以访问成员变量,区分同名的局部变量。
<2>使用地方:所有的OC方法中(对象方法\类方法),不能使用在函数中。
<3>作用:使用“self ->成员变量名”访问当前调用者的成员变量;使用“[self 方法名];”来调用方法(对象方法\类方法)
<4>常见错误:1,用self去调用函数。2,类方法中用self调用对象方法,对象方法中调用类方法。3,self死循环。
//self练习
#import 
@interface Person : NSObject
//声明类方法
+ (void)test;
+ (void)test1;

//声明对象方法
- (void)test;
- (void)test2;
@end

@implementation Person
//实现类方法
+ (void)test
{

    NSLog(@"调用了类的test方法");
//    //会引发死循环
//    [self test];
}
//实现对象方法
- (void)test
{
    NSLog(@"调用了对象的test方法");
    //会引发死循环
    //[self test];
}
//实现类方法
+ (void)test1
{
    //这里self代表的是类
    [self test];
}
//实现对象方法
- (void)test2
{
    //这里self代表的是对象
    [self test];
}
@end

int main()
{
    Person *p = [Person new];
    //调用对象方法
    [p test2];
    //调用类方法
    [Person test1];
    return 0;
}
/*运行结果是:
 2014-04-06 15:12:28.178 a.out[827:707] 调用了对象的test方法
 2014-04-06 15:12:28.181 a.out[827:707] 调用了类的test方法
 */
4,继承
<1>继承的好处:1,抽取重复代码;2,建立了类之间的关系;3,子类可以拥有父类中的所有成员变量和方法。坏处:耦合性太强。
注意点:基本上所有的类的根类都是NSObject类。
//继承的代码体现

#import 
//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类的声明,Dog继承Animal
@interface Dog : Animal

@end
//Dog类的实现
@implementation Dog
@end

//Cat类的声明,Cat继承Animal
@interface Cat : Animal

@end
//Cat类的实现
@implementation Cat
@end

int main()
{
    //创建Dog对象
    Dog *d = [Dog new];
    //给age赋值
    [d setAge:5];
    //给weight赋值
    [d setWeight:30];
    NSLog(@"age=%d,weight=%0.1f",[d age],[d weight]);
    
    //创建Cat对象
    Cat *c = [Cat new];
    //给age赋值
    [c setAge:6];
    //给weight赋值
    [c setWeight:10];
     NSLog(@"age=%d,weight=%0.1f",[c age],[c weight]);

    return 0;
}
/*运行结果是
 2014-04-06 16:22:26.308 a.out[978:707] age=5,weight=30.0
 2014-04-06 16:22:26.310 a.out[978:707] age=6,weight=10.0
 */
<2>继承的应用
#1,重写:子类重新实现父类中的某个方法,覆盖父类以前的做法。
#2,父类必须声明在子类的前面;子类不能拥有父类相同的成员变量;调用某个方法时,优先去当前类中找,如果找不到,去父类中找。
#import 
//声明Person类
@interface Person : NSObject
{
    //定义成员变量
    NSString *_name;
    int _age;
    
}
//声明类方法
+ (void)test;
//声明name的set方法
- (void)setName:(NSString *)name;
//声明name的get方法
- (NSString *)name;

//声明age的set方法
- (void)setAge:(int)age;
//声明age的get方法
- (int)age;
//声明run方法
-(void)run;
@end

//实现Person类
@implementation Person
//实现类方法
+ (void)test
{
    NSLog(@"我是Person类的类方法!!!");
}
//实现name的set方法
- (void)setName:(NSString *)name
{
    _name = name;
}
//实现name的get方法
- (NSString *)name;
{
    return _name;
}

//实现age的set方法
- (void)setAge:(int)age
{
    _age = age;
}
//实现age的get方法
- (int)age;
{
    return _age;
}
//实现run方法
- (void)run
{
    NSLog(@"名字叫%@,年龄是%d的人在跑步",_name,_age);
}
@end
//声明Student子类并且继承了Person父类
//不允许子类和父类拥有相同名称的成员变量
@interface Student : Person
{
    //定义成员变量
    int _no;
}
+ (void)test1;
- (void)setNo:(int)no;
- (int)no;
@end
//实现Student类
@implementation Student
+ (void)test1
{
    //调用test方法,先在本类中找,如果没有,然后再去父类中找,
    [self test];
}

- (void)setNo:(int)no
{
    _no = no;
}
- (int)no
{
    return _no;
}

//重写父类Person的run方法
- (void)run
{
    NSLog(@"学号为%d,名字叫%@,年龄为%d的学生在跑步",_no,_name,_age);
}
@end

int main()
{
    //创建Student类对象
    Student *s = [Student new];
    //设置学号
    [s setNo:20140010];
    //设置名字
    [s setName:@"张三"];
    //设置年龄
    [s setAge:23];
    //调用子类重写后的run方法
    [s run];
    //调用类方法
    [Student test1];
    return 0;
}
/*运行结果是
 2014-04-06 18:04:56.342 a.out[1104:707] 学号为20140010,名字叫张三,年龄为23的学生在跑步
 2014-04-06 18:04:56.345 a.out[1104:707] 我是Person类的类方法!!!
 */
<3>继承的使用场合及组合使用

1> 当两个类拥有相同属性和方法的时候,就可以将相同的东西抽取到一个父类中
 2> 当A类完全拥有B类中的部分属性和方法时,可以考虑让B类继承A类
 A
 {
    int _age;
    int _no;
 }
 
 B : A
 {
    int _weight;
 }
 // 继承:xx 是 xxx
 // 组合:xxx 拥有 xxx
 2.组合
 A
 {
    int _age;
    int _no;
 }
 
 B
 {
    A *_a;
    int _weight;
 }
<4>super 的作用

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

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

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

5,多态

<1>多态的基本概念:某一事物的多种形态;OC对象具有多态性。多态:不同对象对同一消息的不同响应.子类可以重写父类的方法。
<2>多态使用

#1.没有继承就没有多态

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

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

 #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
{
    NSLog(@"Dog吃东西");
}
@end
int main()
{
    //Dog类的多态表现,Animal父类指针指向Dog子类对象
    Animal *a = [Dog new];
    // 调用方法时会检测对象的真实形象
    [a eat];
     // 多态的局限性:父类类型的变量不能用来调用子类的方法,直接调用会有警告!
    /*4-多态.m:38:8: warning: 'Animal' may not respond to 'run'
     [a run];
     ~ ^
     1 warning generated.
     */
    //所以将a转换为Dog类型
    Dog *d = (Dog *)a;
    [d run];
    return 0;
}
/*运行结果为:
 2014-04-06 19:41:16.678 a.out[1301:707] Dog吃东西
 2014-04-06 19:41:16.679 a.out[1301:707] Dog跑起来了
 */


你可能感兴趣的:(基础篇)