標籤:style blog http color java 使用 os io
前言:
繼承這點事,說多不多,說少不少,這裡只描述了一些我認為的基礎篇,望各位大神指教。
本節參照了C#進階編程和Think in java對繼承的描述,我個人認為OOP只是思想,故看明白一個就說通的,只是文法上的區別。
- 許可權限制關鍵字
- 類繼承
- 類繼承基本寫法
- 類繼承的好處
- 繼承中的Virtual(虛方法)
- 抽象類別
- 類繼承的壞處
- 執行循序
- 不可繼承的類
- 介面繼承
1.類繼承 類繼承基本寫法:
public class SuperClass : Object{} public class SubClass : SuperClass{}
我們用":"來表示類的繼承, 而且每個類只能有一個父類(這個靠譜啊,你不可能有兩個親身父親,C++不論)。
SuperClass繼承了Object類, Object類是頂級類,你自訂的頂級類(這裡說SuperClass)會自動繼承這個類(我看有很多人說:你的每個類都會繼承Object,我們說過,你只能有一個親生父親,這樣的說法不是很嚴謹,這樣的Tier1, Tier2, Tier3的層次下來,你的高層可以直接用Object所開放的一些方法)。
類繼承的好處:
我們先來看些該死的溫柔(類)!!!
public class Dog { public string Name { get; set; } public string Age { get; set; } public void Run() { Console.WriteLine("Dog is running."); } } public class Cat { public string Name { get; set; } public string Age { get; set; } public void Run() { Console.WriteLine("Cat is running."); } }
View Code
粗看一下,沒什麼問題,貓類和狗類 都有名字,年齡和一個跑的方法。 (當年,我寫完還點頭,雙手叉腰,嗯,很好,不錯--傻的一塌糊塗,冏)
但是如果那天有個變態叫你把所有動物都寫一邊,你開始造輪子了,1234567.....,終於要完工了, 大喜過望,那個變態回來告訴你,不好意思,弄錯了,年齡沒有意義,可以去掉(納尼....). 這個時候你就需要再去1234567....,oh Fuck...難道我不能只改一次嗎?
完 全 可 以->繼承
public abstract class Animal { public string Name { get; set; } public string Age { get; set; } public void Run() { Console.WriteLine(string.Format("{0} is running.", Name)); } } public class Dog : Animal { } public class Cat : Animal { }
View Code
代碼所示之處我們提取一個父類:Aniaml(抽象類別..過後再說這個).我們重新來完成那個變態的需求,我們只要開闢一個類然後繼承一下Animal就好了,
(情境恢複)嘿,年齡沒有意義,可以去掉(簡單....),我們只要把Animal中的年齡去掉,就OK了,一步到位。
到這裡看出來繼承的好處沒:消除你重複的代碼,讓修改更加的方便。
繼承中的Virtual(虛方法)
這裡又有人提出另一個問題了,如果我發現我父類的方法不能滿足我的條件了,但是我又不想重載,我能重寫嗎?答案:完全可以。
C#提供一個Virtual的一個標識,可以用於方法重寫(java都說虛方法)
public abstract class Animal { public string Name { get; set; } public string Age { get; set; } public virtual void Run() { Console.WriteLine(string.Format("{0} is running.", Name)); } } public class Dog : Animal { public override void Run() { Console.WriteLine("Dog is running."); } } public class Cat : Animal { }
View Code
看Animal中的Run方法加上了virtual標識這個方法說虛方法,也就說可以被重寫,在Dog類中,我們使用了override標識我們重寫了Run的方法,這樣我們在執行個體化對象Cat的時候,我調用Run方法就是我們重寫過的。
有人提出疑問了:如果不寫virtual 和 override,直接在Cat中重寫Run方法,執行個體化Cat cat=new Cat()後調用Run方法也是一樣的結果。 回答:C#不像JAVA都說虛方法,如果不想寫virtual 和 override的話,CLR認為這個是隱藏,所以要在子類的Run方法上添加一個new關鍵字,如果不添加會出現
warning。
public class Cat:Animal
{
public new void Run()
{
Console.WriteLine("....");
}
}
New 關鍵字代表我要隱藏父類同名,同參數的方法(這裡有幾個可以討論的地方,在多態那章會提出來說)
抽象方法
為什麼會出現抽象方法,OOP告訴我們,執行個體化就像我們現實中創造一件東西,就如上例來看,我們如何去創造一個叫Animal的一個實體,這樣是不是很奇怪,所以我們出現了抽象類別。 抽象類別無法被執行個體化,只能被繼承使用。public abstract class Animal,在class前面定義abstract關鍵字就好了。
抽象類別可以定義抽象的方法,用abstract關鍵字來標識,所有繼承該抽象類別的子類必須實現這個抽象方法,來一個執行個體:
public abstract class Animal { public string Name { get; set; } public string Age { get; set; } public virtual void Run() { Console.WriteLine(string.Format("{0} is running.", Name)); } public abstract void Scream(); } public class Dog : Animal { public override void Run() { Console.WriteLine("Dog is running."); } public override void Scream() { throw new NotImplementedException(); } } public class Cat : Animal { public override void Scream() { throw new NotImplementedException(); } }
View Code
在Animal的抽象類別中(我們說了為什麼把Animal定義成抽象類別),定義了一個Scream()的抽象方法,我們看見了。抽象方法是沒有實現體的,直接後面跟上";"作為結束。在子類Dog和Cat類裡,我們實現了Scream這個方法(不可以不實現,只要你用IDE工具,編譯時間會報錯),我們在來看子類的Scream方法有override的關鍵字,所以abstract被認為是虛方法,用法類似。
註:這裡還沒有說介面,抽象類別和介面一起用非常的常見,等說到介面,再詳細的來說下抽象類別的其他作用。
類繼承的壞處
所謂有得必有失,繼承給我們帶來了很多好的地方,消除代碼重複,讓層次更加清晰,修改方便等好處,但是隨之帶來的壞處也是很明顯的,當我們繼承的層次變多了,整個的架構會變得十分臃腫而導致不清晰,拿個簡單的例子來說,假設我們說從猩猩進化而來,那尾巴是否已經沒有了,而猩猩還是有的,這就會導致使用的迷糊,我們做類的時候要把該類的東西放在此類中,做父類的時候把對應的公用的東西提出來,而一直用繼承的話很恐怖,所以這裡又引出一個新的概念->組合。
組合概念就說在類中放一個其他類的對象,如果要用就賦值,不要用了就直接拿掉(父親我們總不能放棄吧)。
執行循序
public abstract class SuperClass { public static string StaticField = "StaticFieldInSuperClass"; private string _privateField = "_privateFieldInSuperClass"; public string publicField = "publicFieldInSuperClass"; public SuperClass() { } } public class SubClass : SuperClass { public static string StaticFieldInDog = "StaticFieldInSubClass"; private string _privateField = "_privateFieldInSubClass"; public SubClass() { } }
View Code
我們看一下這兩個類SuperClass裡面有靜態欄位,私人欄位,共有欄位和一個構造,SubClass有一個靜態欄位,私人欄位。
我們執行個體化SubClass subClass=new SubClass()的時候,執行循序如下:
1.先初始化子類(subclass)的欄位。
2.執行子類構造,這時會發現它擁有父類,所以暫停初始化子類構造,而初始化父類(SuperClass)
3.初始化父類(SuperClass)的欄位
4.執行父類構造
5.返回子類繼續初始化子類構造
這裡有興趣的朋友可以直接debug看步驟就明白了。
不可繼承的類
擁有關鍵字sealed類都不能被繼承。
public sealed class ConfigHelper { }
故可以認為裡面所有的欄位和方法都說內建sealed,因為無法繼承就無法重寫。
2.介面繼承
pending...有點別的事..先發布了..。