Objective-C中的繼承和多態
面向對象編程之所以成為主流的編程思想和他的繼承和多態是分不開的,只要是面向對象語言都支持繼承和多態,當然不同的OOP語言之間都有其特點。OC中和Java類似,不支持多重繼承,但OOP語言C++就支持多繼承,為什麼OC不支持多繼承稍後將會提到。
說到繼承呢,想到了一本書上是引用《大話西游》裡的一句話來描述繼承的。“人是人他媽生的,妖是妖他媽生的!”,想必裡面的唐三藏也學過OOP編程,也許他們師徒四人去西天取什麼算法導論呢,漫談OOP編程啦,數據結構啦等這類的書去啦。人和妖都屬於動物類,但各自有各自的特點,各自有各自的不同,動物就是父類,而人和妖就是子類。繼承的目的是為了減少代碼的冗余,還是DRY原則(don`t repeat yourself)。
在Objective-C中super是指向直接父類的指針,而self是指向本身的指針,self就相當於java中的this指針。在OC中寫類時可以在@implementation中定義哪些在@interface中無相應聲明的方法,但這個方法是私有的,僅在類的實現中使用。
在Objectiv-C中幾乎所有的類都是繼承自NSObject類,NSObject類中存在大量功能強大的方法。下面對NSObject類中的各種方法進行試驗和介紹:
1. +(void) load; 類加載到運行環境時調用該方法
測試:在子類中重寫load方法來進行測試, 當重寫完load方法,在mian方法中不需要任何實例化任何對象
當類被加載時load就會別調用.load是類方法,可以直接被類調用
//重寫NSObject中的load方法
+(void) load
{
NSLog(@"ObjectTest中的load方法被調用啦!!");
}
運行結果:
2014-07-30 08:58:31.704 HelloOC[550:303] ObjectTest中的load方法被調用啦!!
2. +(void) initialize; 在類第一次使用該類時調用該方法,第二次就不調用了
測試:重寫initalize方法
//重寫initialize方法,會在類第一次使用時調用
+(void) initialize
{
NSLog(@"initialize方法被調用了(類第一次被實例化)!");
}
運行結果:
2014-07-30 09:27:53.767 HelloOC[624:303] load方法被調用啦!!
2014-07-30 09:27:53.769 HelloOC[624:303] initialize方法被調用了(類第一次被實例化)!
3. +(id) alloc: 返回一個已經分配好的內存對象; -(id) init: 對已經分配了內存的實例進行初始化; new同時調用了alloc 和 init
demo: Object *object = [[Object alloc] init];
可以在子類中把alloc進行重寫,然後觀察運行情況
//重寫alloc方法
+(id) alloc
{
NSLog(@"alloc函數被調用啦");
return [super alloc];
//重寫init
-(id) init
{
NSLog(@"init被調用了");
self = [super init];
return self;
}
測試方法一個用alloc和init實例化類,一個用new實例化類:
//第一次使用ObjectTest類
ObjectTest *o1 = [[ObjectTest alloc] init];
//第一次使用ObjectTest類
ObjectTest *o2 = [ObjectTest new];
運行結果:
2014-07-30 09:59:58.991 HelloOC[689:303] load方法被調用啦!!
2014-07-30 09:59:58.993 HelloOC[689:303] initialize方法被調用了(類第一次被實例化)!
2014-07-30 09:59:58.993 HelloOC[689:303] alloc函數被調用啦
2014-07-30 09:59:58.993 HelloOC[689:303] init被調用了
2014-07-30 09:59:58.994 HelloOC[689:303] alloc函數被調用啦
2014-07-30 09:59:58.994 HelloOC[689:303] init被調用了
4.-(void)dealloc 釋放對象自身所占有的內存;
5. -(Class)class 或者 +(Class)class 返回當前對象的所屬類; -(Class)superclass 或者 +(Class)superclass返回當前類的父類
//返回當前對象所對應的類
NSString *className =(NSString *) [self class];
NSLog(@"%@類的display方法", className);
//返回當前對象所對應的父類
NSString *superClassName = (NSString *) [self superclass];
NSLog(@"%@類的父類是%@", className, superClassName);
6、-(BOOL)isKindOfClass : (Class)aClass 判斷某個實例是否屬於某個類或者子類的對象
事例代碼如下:
//isKindOfClass的用法
BOOL b = [o2 isKindOfClass:[ObjectTest class]];
if (b == YES) {
NSLog(@"o2是ObjectTest類的對象");
}
7.-(BOOL)isMemberOfClass:(Class)aClass; 只能判斷摸個實例是否屬於某個類,不能判斷是否屬於某個父類;
//isMemberOfClass
BOOL result = [o2 isMemberOfClass:[NSObject class]];
if (result == NO) {
NSLog(@"isMemberOfClass不能判斷是否為NSObject子類的對象");
}
8.-(NSString *) description; 返回字符串形式對象的描述,方便調試
//description
NSString *descript = [o2 description];
NSLog(@"%@", descript);
輸出結果: <ObjectTest: 0x100206650>
9.-(NSUInteger) hash; 返回對象的哈希值;
//hash的用法
NSUInteger hash = [o2 hash];
NSLog(@"%p", hash);
輸出結果:2014-07-30 11:40:35.685 HelloOC[1130:303] 0x100107b70
10.-(BOOL) isEqual:(id)object; 比較兩個對象是否相同,默認是使用地址進行比較的,且hash值一定要相同
//isEqual的用法
NSString *str1 = @"111";
NSString *str2 = str1;
if ([str2 isEqual:str1] == YES)
{
NSLog(@"str2 == str1");
}
else
{
NSLog(@"str2 != str1");
}
Objective-C中的繼承
繼承是is-a的關系,比如貓咪是一個動物,那麼動物是父類,而貓咪是動物的子類。子類具有父類的屬性和 行為,以及自身的屬性和行為,也就是說“父類更一般,子類更具體”。用一個富二代的類來說明一下類的繼承。
1.先定義一個富人的類
代碼說明:
1.聲明訪問權限為@protected的三個屬性,分別為三個屬性用@property加上getter和setter方法
2.並為該類創建便利初始化方法和便利構造器
3.為富人類定義一個刷卡方法
//
// Richer.h
// HelloOC
//
// Created by ludashi on 14-7-29.
// Copyright (c) 2014年 ludashi. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface Richer : NSObject
{
@protected
NSString *name;
int age;
NSString *gender;
}
//定義富人的姓名,年齡,性別,並為其提供getter和setter方法
@property (copy, nonatomic) NSString *name;
@property (assign, nonatomic) int age;
@property (copy, nonatomic) NSString *gender;
//定義便利初始化方法
-(id) initWithName : (NSString *)vName
AndAge : (int)vAge
AndGender : (NSString *)vGender;
//定義便利構造器
+(id) richerWithName : (NSString *)vName
AndAge : (int)vAge
AndGender : (NSString *)vGender;
//定義刷卡方法
-(void) poss;
@end
2.為富人類編寫實現代碼
代碼說明:
1.用@synthesize實現getter和setter方法
2.實現便利初始化方法,用[ super init ]初始化富人類的直接父類,也就是NSObject
3.使用便利構造器返回實例化並初始化後的對象
#import "Richer.h"
@implementation Richer
//實現getter和setter方法
@synthesize name, age, gender;
//實現便利初始化函數
-(id) initWithName : (NSString *)vName
AndAge : (int)vAge
AndGender : (NSString *)vGender
{
if (self = [super init])
{
self->name = vName;
self->age = vAge;
self->gender = vGender;
}
return self;
}
//實現便利構造器
+(id) richerWithName:(NSString *)vName
AndAge:(int)vAge
AndGender:(NSString *)vGender
{
Richer *richer = [[Richer alloc] initWithName:vName
AndAge:vAge
AndGender:vGender];
return richer;
}
//實現刷卡方法
-(void) poss
{
NSLog(@"%@有錢你就刷吧", name);
}@end
3.編寫富二代的類,富二代和富人有許多相似的屬性和方法所以富二代繼承於富人類,並添加相應的屬性和方法,把需要重寫的方法進行重寫。
代碼說明:
1.為富二代類添加新的愛好屬性
2.為富二代添加新的方法
#import "Richer.h"
@interface Richer2nd : Richer
//Richer2nd繼承啦Richer所有的方法
//為富二代添加新的屬性
@property (copy, nonatomic) NSString *hobby;
//便利初始化函數
-(id) initWithName : (NSString *) vName
AndAge : (int)vAge
AndGender : (NSString *) vGender
AndHobby : (NSString *)vHobby;
//為Richer2nd編寫便利構造器
+(id)richer2ndWithName : (NSString *) vName
AndAge : (int)vAge
AndGender : (NSString *) vGender
AndHobby : (NSString *)vHobby;
//添加hobby方法
-(void) myHobby;
@end
4.各種方法的實現
代碼說明:
1.在編寫便利初始化方法時利用super來調用父類的便利初始化方法來把繼承到的父類的方法進行初始化
2.用self給新添加的屬性進行初始化
#import "Richer2nd.h"
@implementation Richer2nd
//實現屬性的getter和setter方法
@synthesize hobby;
//編寫便利初始化函數,復用父類的便利初始化方法
-(id)initWithName:(NSString *)vName
AndAge:(int)vAge
AndGender:(NSString *)vGender
AndHobby:(NSString *)vHobby
{
if (self = [super initWithName:vName AndAge:vAge AndGender:vGender]) {
self->hobby = vHobby;
}
return self;
}
//編寫便利構造函數
+(id)richer2ndWithName:(NSString *)vName
AndAge:(int)vAge
AndGender:(NSString *)vGender
AndHobby:(NSString *)vHobby
{
Richer2nd *richer = [[Richer2nd alloc] initWithName:vName AndAge:vAge AndGender:vGender AndHobby:vHobby];
return richer;
}
//重寫刷卡方法
-(void)poss
{
[super poss];
NSLog(@"我是富二代,我爸有錢,我就刷!");
}
//添加新的方法
-(void) myHobby
{
NSLog(@"我是富二代%@,我超喜歡%@", name, hobby);
}
@end
5.以下是上面代碼的運行結果
2014-07-30 08:38:12.956 HelloOC[483:303] Bill有錢你就刷吧
2014-07-30 08:38:12.957 HelloOC[483:303] BILL`s son有錢你就刷吧
2014-07-30 08:38:12.958 HelloOC[483:303] 我是富二代,我爸有錢,我就刷!
2014-07-30 08:38:12.958 HelloOC[483:303] 我是富二代BILL`s son,我超喜歡飙車
Objective-C中的多態
多態簡單的說就是對於不同對象響應同一個方法時做出的不同反應。在 OC中動態類型id是實現多態的一種方式,id是一個獨特的數據類型,可以轉換為任何數據類型,上面的富人和富二代可以這樣定義
id richer = nil;
//測試富人類
richer = [Richer richerWithName:@"Bill" AndAge:40 AndGender:@"Man"];
[richer poss];
//測試富二代的類
richer = [Richer2nd richer2ndWithName:@"BILL`s son" AndAge:16 AndGender:@"男" AndHobby:@"飙車"];
[richer poss];
[richer myHobby];
上面程序的輸出結果和繼承部分的結果是一致的;
多態的另一個例子: Animal是父類,子類有Cat 和 Dog,子分別重寫了父類中的eat方法;實例化對象的時候可以用下面的方法:
Animal *animal = nil;
//實例化貓的對象
animal = [Cat new];
[animal eat];
//實例化狗的對象
animal = [Dog new];
[animal eat];
面向對象編程中的OCP原則和LSP原則
OCP : Open Closed Principle原則, 對擴展開放,對修改關閉
LSP :裡氏代換原則,任何基類可以出現的地方,子類一定可以出現。