類有三大特性:繼承,封裝,多態:
封裝
封裝就是對類中的一些字段,方法進行保護,不被外界所訪問到,有一種權限的控制功能,Java中有四種訪問權限修飾符:
public,default,protected,private
訪問權限依次遞減,我們在定義類時,哪些字段和方法不想暴露出去,哪些字段和方法可以暴露,可以通過修飾符來完成,這就是封裝;
在OC語言中,使用@interface和@implementation來處理類。
@interface就好像暴露在外面的時鐘表面,像外界提供展示以及接口。@implementation就好像隱藏在時鐘內部的構造實現,把具體的實現封裝了起來。
(ps:@interface 中是成員變量,@implementation 是全局變量)
Car.h
#import
@interface?Car?:?NSObject{
//這個屬性就是對外進行保密的相當于private,所以我們需要在外部訪問的話,必須定義get/set方法
//默認的是private的,但是我們可以使用@public設置為public屬性的,那么在外部可以直接訪問:person->capcity?=?2.8;
//當然我們一般不這么使用,因為這會破壞封裝性,這種用法相當于C中的結構體中權限
//一共四種:@public,@protected,@private,@package,這個和Java中是相同的
@public
float?_capcity;?//油量屬性
}
-?(void)run:(float)t;
@end
這里我們可以看到,OC中也是有四種訪問權限修飾符:
@public、@protected、@private、@package
其中默認的修飾符是@private
但是這里要注意的是:OC中的方法是沒有修飾符的概念的,這個和Java有很大的區別,一般都是公開訪問的,即public,如果想讓一個方法不被外界訪問的話,只需要在.m文件中實現這個方法,不要在頭文件中進行定義,說白了就是:該方法有實現,沒定義,這樣外界在導入頭文件的時候,是沒有這個方法的,但是這個方法我們可以在自己的.m文件中進行使用。
開發過程中,考慮到安全性要求,一般不在成員變量名前面使用@public、@protected等關鍵字修飾,而是使用Set方法來為對象提供成員變量的值。在set方法的內部也可以對一些不合理的賦值進行篩選過濾。
命名規范:
(1)方法名必須以set開頭
(2)Set后面跟上成員變量的名稱,首字母大寫
(3)返回值一定是void
(4)一定要接收一個參數,而且參數類型需要和成員變量的類型一致
(5)形參名不能和成員變量名一樣(蘋果官方推薦成員變量名前加_以示區分)
繼承
繼承是類中的一個重要的特性,他的出現使得我們沒必要別寫重復的代碼,可重用性很高。當然OC中的繼承和Java中是一樣的,沒多大區別,這里在看一個例子吧:
父類:Car
Car.h
#import
@interface?Car?:?NSObject{
NSString?*_brand;
NSString?*_color;
}
-?(void)setBrand:(NSString?*)brand;
-?(void)setColor:(NSString?*)color;
-?(void)brake;
-?(void)quicken;
@end
Car.m
#import "Car.h"
//引入頭文件
@implementation?Car
-?(void)setBrand:(NSString?*)brand{
_brand?=?brand;
}
-?(void)setColor:(NSString?*)color{
_color?=?color;
}
-?(void)brake{
NSLog(@"剎車");
}
-?(void)quicken{
NSLog(@"加速");
}
@end
方法的實現
在來看一下子類:
Taxi.h
#import "Car.h"
@interface?Taxi?:?Car{
NSString?*_company;//所屬公司
}
//打印發票
-?(void)printTick;
@end
Taxi類繼承了父類Car, 需要導入父類的頭文件,在Taxi類中多了Car 的一個屬性和方法
Taxi.m
#import "Taxi.h"
@implementation?Taxi
-?(void)printTick{
[super?brake];
[self?brake];
NSLog(@"%@出租車打印了發票,公司為:%@,顏色為:%@",_brand,_company,_color);
}
@end
對方法的實現,看到實現文件中是不需要導入父類Car的頭文件的,因為可以認為,Taxi.h頭文件中已經包含了Car的頭文件了。
而且,這里可以使用super關鍵字來調用父類的方法,也是可以用self關鍵字來調用,這里看到其實這兩種方式調用的效果是一樣的,當子類重新實現brake方法的時候(Java中的重寫概念)。
那么這時候super關鍵字調用的還是父類的方法,而self調用的就是重寫之后的brake方法了。同樣,我們也是可以使用父類中的屬性。
附上一句理解的話就是,老爸就是超級的,自己的就是self
Train.h
#import "Car.h"
//火車類繼承Car
@interface?Train?:?Car{
float?_maxWeight;//最大載貨量
}
//覆蓋父類的方法brake
//優先調用子類的方法
-?(void)brake;
-?(void)unload;
@end
自己定義了一個brake方法,這時候就會覆蓋父類中的brake方法了。
Train.h
#import "Train.h"
@implementation Train
-?(void)brake{
[super?brake];
NSLog(@"Train類中的brake方法");
}
-?(void)unload{
[super?brake];//調用父類的方法
[self?brake];//也是可以的
NSLog(@"%@的火車卸貨了,載貨量:%.2f,車的顏色:%@",_brand,_maxWeight,_color);
}
@end
可以看到,在brake方法中調用一下父類的brake方法,然后在實現自己的邏輯代碼。
多態
大學上了三年多的課,無時無刻都在聽到多態這個詞,但是以前感覺自己不認真,也沒怎么重視這個東西,其實這東西一直很重要這是真的。
Printer.h
#import
@interface?Printer?:?NSObject
-?(void)?print;
@end
Printer.m
#import "Printer.h"
@implementation?Printer
-?(void)print{
NSLog(@"打印機打印紙張");
}
@end
PrinterCorl.h
#import "PrinterCor.h"
//修改父類的打印行為
@interface?ColorPrinter?:?Printer
-?(void)print;
@end
PrinterCorl.m
#import "PrinterCorl.h"
@implementation ColorPrinter
-?(void)print{
NSLog(@"彩印");
}
@end
BlackPrinter.h
#import "BlackPrinter.h"
@implementation?BlackPrinter
-?(void)print{
NSLog(@"黑白打印機");
}
@end
這里我們在定義一個Person類,用來操作具體的打印機
Person.h
@implementation Person
- (void)doPrint:(Printer *)printer{
}
@end
Person.m
#import "Person.h"
@implementation?Person
/*
-?(void)?printWithColor:(ColorPrinter?*)PrintCorl{
[colorPrint?print];
}
-?(void)?printWithBlack:(BlackPrinter?*)blackPrint{
[blackPrint?print];
}
*/
-?(void)?doPrint:(Printer?*)printer{
[printer?print];
}
@end
main.m
#import "Person.h"
#import?"BlackPrinter.h"
#import?"PrinterCorl.h"
int?main(int?argc,?const?charchar?*?argv[])?{
@autoreleasepool?{
Person?*person?=[[Person?alloc]?init];
PrinterCorl *colorPrint?=?[[ColorPrinter?alloc]?init];
BlackPrinter?*blackPrint?=?[[BlackPrinter?alloc]?init];
//多態的定義
/*
Printer?*p1?=?[[ColorPrinter?alloc]?init];
Printer?*p2?=?[[BlackPrinter?alloc]?init];
[person?doPrint:p1];
[person?doPrint:p2];
*/
//通過控制臺輸入的命令來控制使用哪個打印機
int?cmd;
do{
scanf("%d",&cmd);
if(cmd?==?1){
[person?doPrint:colorPrint];
}else?if(cmd?==?2){
[person?doPrint:blackPrint];
}
}while?(1);
}
return?0;
}
下面就來詳細講解一下多態的好處
上面的例子是一個彩色打印機和黑白打印機這兩種打印機,然后Person類中有一個操作打印的方法,當然這個方法是需要打印機對象的,如果不用多態機制實現的話(Person.h中注釋的代碼部分),就是給兩種打印機單獨定義個操作的方法,然后在Person.m(代碼中注釋的部分)中用具體的打印機對象進行操作,在main.m文件中,我們看到,當Person需要使用哪個打印機的時候,就去調用指定的方法:
這種設計就不好了,為什么呢?假如現在又有一種打印機,那么還需要在Person.h中定義一種操作這種打印機的方法,那么后續如果在添加新的打印機呢?還在添加方法嗎?那么Person.h文件就會變得很臃腫。所以這時候多態就體現到好處了,使用父類類型,在Person.h中定義一個方法就可以了:
-?(void)?doPrint:(Printer?*)printer;
這里看到了,這個方法的參數類型就是父類的類型,這就是多態,定義類型為父類類型,實際類型為子類類型
-?(void)?doPrint:(Printer?*)printer{
[printer?print];
}
這里調用print方法,就是傳遞進來的實際類型的print方法。
Printer?*p1?=?[[ColorPrinter?alloc]?init];
Printer?*p2?=?[[BlackPrinter?alloc]?init];
[person?doPrint:p1];
[person?doPrint:p2];