教面試官ReentrantLock源碼
663
2025-04-03
繼承
在現實生活中有所謂的“種瓜得瓜、種豆得豆”的說法,在生物學概念上就是“遺傳”的概念,在面向對象中“繼承”就類似于生物學中的遺傳,通過繼承,可以更好的實現代碼的重用(復用,多次使用的意思)、增加擴展性、簡化代碼等。
下面是現實生活中的引用:
定義與使用繼承
繼承一次最常用的就是通過合法程序(比如遺囑)從別人那里接受財產或爵位等,有點類似于世襲制。
另外一個含義,是人從父母那里繼承一些特征,如果孩子從父母繼承的身高、相貌等特征。那么在什么情況下使用繼承,以及在程序中應該如何定義呢?
首先,繼承一般使用在類之間有一定的層次關系,即一個類已經包含了其他類的一些屬性與方法,比如,雇員類包含了技術員工、客服員工、軟件支持、經理等的屬性和方法,這時,我們把雇員類成為父類,技術員工等類成為子類,子類可以通過繼承機制來使用父類的屬性和方法。
概括來說:繼承需要is a的關系(技術員工 is a 雇員)
在C#中,使用“:”來表示一個類繼承自另外一個類。格式如下:
class?? 技術員工:雇員
{
//技術員工的屬性定義
// 技術員工的方法定義
}
現在需要你為一家卡通影視公司開發商業軟件,其中涉及一個會說話的鴨子(比如唐老鴨),在此之前已經有了,普通鴨子類了。代碼如下:
Class Duck
{
private??? string name;
public string Name
{
get{return name;}
set{name=value;}
}
public void Quck()
{
Console.WriteLine(“嘎嘎嘎”);
}
public void Swimming()
{
Console.WriteLine(“游啊游”);
}
}
那么,現在唐老鴨會說人話,怎么辦呢?同時還會“嘎嘎嘎”叫,原來的方式是在Duck類里增加方法
public void Speak()
{
Console.WriteLine(“說人話了^.^”);
}
然后在Main()方法中調用,使用繼承后的方法:
class TangDuck:Duck
{
public void Speak()
{
Console.WriteLine(“說人話了^.^”);
}
}
同理可以在Main()中進行類的聲明與調用
static void Main(string[]args)
{
TangDuck tanglaoya=newTangDuck();
tanglaoya.Speak();????????????? //可以實現說話功能
}
我們看到類TangDuck在使用繼承實現Speak時,在類名后跟了個“:”,冒號在此處的含義為“繼承自”的意思。繼承特點如下:
1.有助于代碼的重用;
2.代碼維護和書寫都簡單得多;
3.父類的可繼承數據成員和方法可用于子類;
4.子類可以輕易的獲得數據成員和方法;
編碼實踐:試完成作業1
深入理解繼承
1.訪問修飾符在繼承中的使用范圍
3.繼承的單根性
4.繼承自上而下是一種逐層具體化的過程,而自下向上是一種逐層抽象化得過程,這種抽象化關系反應為上下層之間的繼承關系。例如:最高層的動物具有最普遍的特征,而最底層的人則具有較具體的特征。
項目1:使用訪問修飾符深入學習繼承
項目背景:實現雇員類對人類的代碼重用。
解決方案:學習如何利用繼承機制來實現代碼重用。
任務1:編寫代碼
using System;
usingSystem.Collections.Generic;
usingSystem.Text;
namespaceExtends
{
class Person
{
//字段
private stringname;
private stringaddress;
private stringage;
private stringemail;
//屬性
public stringName
{
get{ return name; }
set{ name = value; }
}
protected stringAddress
{
get{ return address; }
set{ address = value; }
}
public stringAge
{
get{ return age; }
set{ age = value; }
}
internal stringEmail
{
get{ return email; }
set{ email = value; }
}
//方法
public voidShowName()
{
Console.WriteLine("姓名:" + name);
}
protected voidShowAddress()
{
Console.WriteLine("地址:" + address);
}
private voidShowAge()
{
Console.WriteLine("年齡:" + age);
}
internal voidShowEmail()
{
Console.WriteLine("郵件:" + email);
}
//構造函數
public Person()
{
name = "活人";
address = "人世間 ";
age = "1";
email = "haoren@163.com";
}
}
class Employee:Person????//Employee類繼承自Person類
{
//字段:部門
private floatdepartment;
//Employee類的方法
public voidShow()
{
Console.WriteLine(Name+ Address + Email);
}
}
class Program
{
static voidMain(string[]args)
{
EmployeetangJun = new Employee();
tangJun.ShowName();
tangJun.Name = "唐峻 ";
tangJun.ShowEmail();
tangJun.Show();
}
}
}
任務2:編譯程序:
任務3:運行效果
姓名:活人
郵件:haoren@163.com
唐峻 人世間 haoren@163.com
base和this關鍵字
通過前面的學習,我們知道子類只能繼承父類非private的屬性和方法,系統在創建對象時必須調用類的構造方法,那么在創建子類對象時父類的構造方法是怎樣被調用的呢?示例如下:
using System;
namespace ExtendsExam
{
classMyBase
{
publicMyBase()
{
Console.WriteLine(“基類對象被創建”);
}
~MyBase()
{
Console.WriteLine(“基類對象被銷毀”);
}
}
class SubClass :MyBase()
{
public SubClass()
{
Console.WriteLine(“子類對象被創建”);
}
~SubClass()
{
Console.WriteLine(“子類對象被銷毀”);
}
}
classProgram
{
static void Main(string[]args)
{
SubClass sc=new SubClass();
}
}
}
運行效果:
基類對象被創建
子類對象被創建
子類對象被銷毀
基類對象被銷毀
通過上述的案例,我們會發現子類自動調用了父類的構造函數和析構函數。如果父類有多個構造函數(即父類構造函數重載的情況),子類如何知道調用父類的那個構造函數呢?此時,用base關鍵字指定調用父類的具體構造函數就比較有用。
base的使用:
n???????調用父類的屬性和方法
public voidDoWork()
{
string message = string.Format(
" {0}上班了,時間{1}",
base.Name, base.Time);
}
n???????調用父類的構造函數
publicManager(string name, Genders gender,
int age,string position,int allowance)
:base(name,gender,age)
{
//經理類擴展的屬性
this.position = position;
this.allowance = allowance;
}
案例:
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Text;
namespace Test
{
class Person
{
protected stringname;
public stringName
{
get{ return name; }
}
public Person(string_name)
{
name = _name;
}
public voidShowName()
{
Console.WriteLine("name={0}", name);
}
}
//Person類的子類
class Employee:Person
{
public stringid;
public Employee(stringsname,string sid):base(sname)
{
id = sid;
}
public voidShow()
{
base.ShowName();??????? //利用base調用方法
Console.WriteLine("name={0}",base.name);??//利用base調用父類字段
Console.WriteLine("id={0}", id);
}
}
class Program
{
static voidMain(string[]args)
{
Employeeemp = new Employee("聶亞龍","MS007");
emp.Show();
}
}
}
this關鍵字:用來調用本類成員
通常也可以隱藏this,MSDN總結如下:
·????????????????限定被相似的名稱隱藏的成員,例如:
public Employee(string name, string alias)
{
this.name = name;
this.alias = alias;
}
·????????????????將對象作為參數傳遞到其他方法,例如:
CalcTax(this);
this指代對象本身,用于訪問本類的常量、字段、屬性和方法,而且不管訪問元素師任何訪問級別。另外,靜態成員不是對象的一部分,因此不能在靜態方法中引用this。
抽象類定義及其使用
在理解抽象類和抽象方法之前,我們先來看一下“抽象”是什么意思,漢語詞典“抽象”含義如下:
1.????? 將復雜物體的一個或幾個特性抽出去,而只去注意其他特性的行動或過程(主要看是否與系統研究的目標一致)
2.???將幾個有區別的物體的共同性質或特性形象地抽取出來或孤立地進行考慮的行動或過程。
3.???抽象對于將東西分類是必需的。
4.???摘要、提煉,抽象化。
從詞典解釋,我們會發現程序里的抽象理論實際上是在仿效現實中的抽象理論和方法。
抽象類:好比一篇摘要,摘要中涉及的很多要點都要在文章的各個部分實現,同樣抽象類功能需要子類來實現。
我們在查找某篇文章時往往先看摘要,摘要可以代表這篇文章,也同樣通過查看抽象類你可以明晰子類提供的功能,并且抽象類對象也可以代表子類實例行使功能。
抽象類最重要的三個描述:
n????? 抽象類是子類的一個描述
n????? 抽象類不能自己實例化,但可以代表子類實例
n????? 抽象類和接口都是用來實現抽象的。
定義如下:
訪問修飾符? abstract?class 類名
{
抽象類體
}
抽象類定義示例:
publicabstract class Employee
{
protected string nid;
public abstract int GetSalary();
public abstract int Name{get;set;}
}
抽象類的定義和普通類的定義非常相似,只是在class和類的訪問修飾符中間加了一個abstract關鍵字。抽象類面可以定義抽象方法、抽象屬性等。抽象類只是用來描述功能,所以這些抽象的方法、屬性等不需要去實現它,只寫個空殼就可以了。
抽象類的使用:
抽象類不能自己實例化,需要使用其子類來實例化。那么抽象實例怎樣才能代表子類實例行使子類功能呢?C#中提供了一種重寫的機制來完成這個功能。重寫關鍵字為override,子類使用該關鍵字來重寫基類的抽象方法、抽象屬性等(注意:凡是子類繼承了抽象類,就必須重寫抽象類里的抽象方法,否則編譯出錯)。
/*抽象類案例*/
usingSystem;
abstractclass BuRuDongWu?? //抽象類:哺乳動物類
{
//成員變量
protected int legs;
protected BuRuDongWu(int legs)
{
this.legs=legs;
}
//抽象方法
public abstract void eat();
//Console.WriteLine("我有方法體");
//抽象方法做實現了嗎?? 抽象方法 體現哺乳動物有一個吃的行為就行了,已經代表了所有子類的吃的行為...
//抽象方法沒有方法體(不允許有方法體);可以常規方法
public int getLegs()? //常規方法,獲得腿數.
{
return legs;
}
}
classDog:BuRuDongWu??????????? //狗類繼承自抽象類:哺乳動物類
{
public Dog(int legs):base(legs)
{}
//子類必須實現所有的抽象方法,通過重寫.
public override void eat()?????????? //注意,重寫方法相當于子類實現了父類的抽象方法
{
Console.WriteLine("狗吃肉");
}
}
classCat:BuRuDongWu
{
public Cat(int legs):base(legs)
{}
public override void eat()?????????? //注意,重寫方法相當于子類實現了父類的抽象方法
{
Console.WriteLine("貓吃老鼠");
}
}
classTest
{
static void Main(string[]args)
{
//BuRuDongWu? lv=new BuRuDongWu();??? 實踐證明抽象類不能被實例化;
//抽象類必須被子類繼承實現,才能體現功能;?--->更好的體現,繼承特性;
Dog underDog=new Dog(4);
Cat? lanMao=newCat(4);
underDog.eat();
lanMao.eat();
Console.WriteLine("狗有{0}條腿,貓有{1}條腿",underDog.getLegs(),lanMao.getLegs());
}
}
為什么要使用父類對象指向子類對象實例呢?留給大家思考。
接口—概念、理解、本質
從現實生活中可以知道,接口是一套規范,遵守這個規范就可以實現功能(比如、用U盤來回拷貝東西、用鼠標操作電腦、用攝像頭和電腦建立連接)。
例如,將電器的“開”、“關”行為單獨定義為一個接口,這樣凡是繼承自這個接口的電器就都有了“開”、“關”的方法。讓電燈、電視、電扇、電冰箱都繼承并實現“開關”接口,這樣,對于所有電器來說都有了自己的開關,并且可以針對本身做相應開關的定義。
接口的定義:
訪問修飾符? interface 接口名?? //名稱通常以I開頭
{
接口內容
}
與抽象類一樣,接口里面的方法成員也不能有方法體;
類可以繼承自接口,繼承之后必須實現里面的所有方法;
接口不能被實例化;
類在實現接口里的方法的時,不需要使用override關鍵字,直接實現即可。
5.C#中接口不能包含任何數據成員;
6.接口內的訪問修飾符不需要些,默認為public。
//接口示例
using System;
interface OnOff? //開關接口
{
void On();
void Off();
}//實現接口的類必須實現接口的所有成員(成員變量、成員方法....);
class Light:OnOff??? //燈
{
public void On()???? //Light類繼承了OnOff接口,在自己的類中對接口中的2個方法來做實現.
{
Console.WriteLine("電燈亮了");
}
public void Off()
{
Console.WriteLine("電燈關了");
}
}
class TV:OnOff
{
public void On()???? //TV類繼承了OnOff接口,在自己的類中對接口中的2個方法來做實現.
{
Console.WriteLine("電視亮了");
}
public void Off()
{
Console.WriteLine("電視關了");
}
}
class Test
{
static void Main(string[]args)
{
Light meDeng=new Light();
meDeng.On();
meDeng.Off();
TV meTv=new TV();
meTv.On();
meTv.Off();
}
}
接口的使用基本上和抽象類一樣,有人把接口比做雙節棍中的一節,另外一節就是繼承并實現接口的類,只有兩節聯合起來使用才會發生效力。
另外,在C#中接口是多繼承的,接口之間可以互相繼承與多繼承、普通類或抽象類也可以繼承自接口(注意接口不能繼承自類或抽象類),一個類可以同時繼承自類和多個接口。
u??? 接口與接口之間
接口與接口之間可以互相繼承,繼承的規則和類一樣,即子接口將獲得父接口的內容。
interface Irun{void run();}??? //跑動
interface Iswim{void swim();}?? //游泳
interface Itwo:Ifly,Iswim{}??? //同時實現跑動與游泳
class TwoTank:Itwo
{?????? //自己的兩棲坦克
public void run(){…}
public void swim(){…}
}
u??? 接口、抽象類和類
interface IA{void playA{};}
interface IB{void playB{};}
abstract class TC
{
public abstract? void playC();
}
class TD:TC,IA,IB
{…}
面向接口的編程:
設計模式的祖師GoF,有句名言:Program to an interface,not an implementation,表示對接口編程而不要對實現編程,更通俗的說法是對抽象編程而不是對具體編程。
微軟的FCL(基礎類庫),是微軟的一幫牛人已經定義好了的東西,如果你理解了接口,就會發現FCL類庫中使用到了很多接口技術。比如數組Array類:
publicabstractclass Array :ICloneable,
IList,ICollection,IEnumerable
,實現了System.Collections命名空間下的Ienumerable接口,那么我們可以用此數組來操作數組元素:
int []a=new int[]{1,2,3,4,5};
System.Collections.Ienumerator it=a.GetEnumerator();
while(it.MoveNext())
{
Console.WriteLine(it.Current.ToString());
}
實踐問題:
選擇題:
1.??????下面哪個不是類?
小結:
在本章中,我們主要學習了:
u??????繼承的定義及其使用
u??????什么是抽象類及重寫
u??????接口的定義與使用
英語詞匯:
英文????????????全文????????????????????????????????????????中文
Base??????????????????????????? 基礎的,基類
Derived???????????????????????? 派生的,繼承的
Point?????????????????????????? 點
Abstract??????????????????????? 抽象的
Virtual???????????????????????? 虛的
Animal????????????????????? 動物
Sealed????????????????????? 封裝的
Method????????????????????? 方法
Interface?????????????????????? 接口
Declare???????????????????????? 聲明
Update????????????????????? 更新
Item??????????????????????? ????? 項
Override??????????????????????? 重載
Furniture?????????????????????? 家具
Bookshelf?????????????????????? 書柜
練習項目:
1請編碼實現某軟件公司員工的繼承關系:
雇員(Animal)具有行為:上班、工作、下班
雇員包括:技術員工,客服、銷售
這些員工工作的行為各不相同;但上班、下班的行為是一致的。
C# 容器
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。