一、復習
1)方法的重載
方法的重載並不是一個方法,實際上方法的重載就是一些不同的 方法,目的是為了方便程序員編碼,所以將功能相近的方法命名相同
根據參數,編譯器自動的去匹配方法體,而不需要程序員記住 的方法
--》如何判斷重載寫的對不對
將方法的定義拿出來,去掉修飾符,去掉方法體,去掉返回類型
int InputNum() int InputNum(int max) int InputNum(int min,int max)
-->將參數列表中的局部變量名去掉,只留參數類型
int InputNum() int InputNum(int ) int InputNum(int ,int )
二、封裝
-》屬性是對字段的封裝
-》 方法是對過程的封裝
-》類是對對象的封裝(特性和功能)
-》程序集是對類庫的封裝
為什麼使用繼承?
-》代碼的重用
-》實現多態(裡氏轉換)
繼承中類分為父類(基類)與子類(派生類)
基類
將具有共同特征的這個類,單獨寫出來,稱為父類(基類)
子類
繼承父類所有的特征,也可以有屬於自己不同的特征。
父類(基類):把這個類的對象都具有的一些特征和行為等都封裝到這個類裡面。
然後由這個父類派生出子類(派生類),這些子類會把父類裡的特征(屬性)行為(方法)等繼承下來。從而實現代碼的重用
例如:
class Person { string _name; int _age; char _sex; public string Name { get { return _name; } } public int Age { get { return _age; } } public char Sex { get { return _sex; } } public Person(string name,int age,char sex) { _sex = sex; _name = name; _age = age; } public void SayHello() { Console.WriteLine("大家好,我叫{0},今年{1}歲了,我是{2}生",_name ,_age ,_sex ); } } class student : Person { public student(string name,int age,char sex):base(name,age,sex) { //方法體 } public void SayHello() { Console.WriteLine("大家好,我叫{0},今年{1}歲了,我是{2}生",Name ,Age ,Sex ); } }
這裡student類是person的派生類,它繼承了person類的所有成員包括SayHello方法,這裡Student的sayhello方法把父類的sayhello方法給隱藏了
繼承的特征
-》單根性(只能繼承一個基類)
-》傳遞性(子類可以繼承基類的成員。字段、屬性、方法等)
-》 派生於object根類(基於C#)(為什麼要有根類?還是為了實現多態)
注意問題
-》構造方法的問題
創建對象的時候,好像是先調用子類構造方法,然後由子類再調用父類構造方法,
再調用構造方法的時候,其實默認有一個base(),調用了父類的無參構造方法
語法:
class 基類
{
//基類成員
}
class 子類:基類
{
//子類可以有自己的成員
//基類的成員也會被繼承下來
}
子類於父類構造方法的執行順序
Student student = new Student();
這裡New子類對象時會先走到子類的構造方法,這裡系統會默認提供一個base()無參的構造方法。如果父類中有了有參的構造方法,系統就不會再分配無參的構造方法,
此時如果子類調用父類的構造方法就會報錯,因為父類的無參構造方法已經沒有了。解決辦法由兩個
1)再手動在父類中添加一個無參的構造方法。
2)base(參數列表)傳參數上去。
public student(string name,int age,char sex):base(name,age,sex) 這裡不執行下面的大括號,然後base調用父類的構造方法,如果父類上面還有父類會依次往上調,
直到調到最上面的父類執行完最上面的父類構造方法然後再依次的往下執行回到這個子類,執行剩下的方法體
{
//方法體
}
this和base關鍵字:
this表示當前類 當前構造方法
base表示父類 父類構造方法
經典例子:
class MyClass { public MyClass():this(3) { Console.WriteLine(1); } public MyClass(int i):this(2,3) { Console.WriteLine(i); } public MyClass(int i, int j) { Console.WriteLine("{0}{1}",i,j); } } class Program { static void Main(string[] args) { MyClass myclass = new MyClass(); } }
在new對象時首先會跳到無參的構造方法,此時看到有一個this(3),不執行方法體,在本類中尋找匹配帶一個參數的構造函數,然後調用,
此時又看到一個this(2,3),又在本類中尋找匹配帶兩個參數的構造函數,最後調用帶兩個參數的構造函數,執行帶兩個參數的方法體,
完畢之後又回到帶一個參數的構造函數中執行方法體,最後再跳會無參的構造函數中執行無參的構造函數的方法體。
四、訪問修飾符
privete 只有在本類中訪問
public 任何地方都可以訪問
protected 只能在當前類和子類中訪問
internal 只允許在當前類中訪問
protectecd internal
裡氏轉換
1)子類可以直接賦值給父類(子類對象可以直接轉換為父類對象)隱式轉換
2)如果滿足第一個條件的父類對象,可以強制轉換為原來的子類對象。 強制轉換
強制轉換可以通過 is 和 as 來判斷
is:
語法 bool b=要轉換的對象 is 要轉換的類型
如果可以轉換就會返回一個true,如果轉換不合法就會返回一個false.
IS操作符很清晰,但是操作效率不高,另種方式是AS
as:
語法 要轉換的類型 對象=要轉換的對象 as 要轉換的類型
as操作首先測試是否合法,如果合法就轉換,如果不合法就返回null,null表示空引用
五、new和override
new隱藏基類方法: 前提是子類和父類的方法名參數返回值都一樣,這時候寫new和不寫new沒上面區別。
class MyBase { public void Func() { Console.WriteLine("我是父類"); } } class MySub : MyBase { public void Func() { Console.WriteLine("我是子類"); } }
這時候子類的方法會把父類的方法隱藏掉,這時候對象是什麼類型就調用什麼類型的方法。
override重寫基類方法:子類要重寫基類的方法,父類的方法必須要有virtual 表明是虛方法,可以被子類重寫。
一旦父類的方法被重寫,父類的方法將不復存在,調用的時候會調用重寫之後的新的方法。
class Person //基類人類
{
//如何在子類中訪問父類的字段
//分別定義三個字段 屬性
//字段的訪問修飾符設定為 protected 這樣在子類中便可以訪問這個字段
//protected表示當前類和子類可以訪問
protected string _name; public string Name { get { return _name; } } protected int _age; public int Age { get { return _age; } } protected char _gender; public char Gender { get { return _gender; } }
//寫一個構造方法 將字段初始化賦值
public Person(string name, int age, char gender) { this._name = name; this._age = age; this._gender = gender; }
//定義一個無參的構造方法,這樣的話子類才能調用父類的構造函數,避免子類要調用無參的構造方法時出錯。
public Person() { } }
//定義一個supperman子類 繼承自 person
class SupperMan : Person { //子類獨有字段 特征 private string _state; public string State { get { return _state; } } public SupperMan(string name, int age, char gender, string state) //這裡不寫base()默認調用父類無參的構造方法,寫與不寫都一樣 { base._name = name; base._age = age; base._gender = gender; base._state = state; //*this 是表示這是該類中的一個字段 //*base則表示這是一個從父類中繼承過來的字段 //*在這裡 this 與base可以不寫 是寫給程序員看的 } public void Hello() { Console.WriteLine("大家好,我叫{0},我的年齡是{1},我是{2}人,我的特征是{3}",Name,Age,Gender,State); } } class Program { static void Main(string[] args) { SupperMan supperMan = new SupperMan("超人", 28, '男', "內褲外穿"); supperMan.Hello(); Console.ReadKey(); } }
2)構造方法
--》沒有繼承關系
-》默認構造方法(無參的構造方法)
沒有提供構造方法的時候, 系統自動的添加一個無參的構造方法
如果已經寫了構造方法,那麼系統就不會自動的添加默認的構造方法(手動添加)
-》構造方法也有重載
調用
this(當調用制定構造方法後有this的時候,會先調用this表示的重載,再調用自己的構造方法)
--》有繼承關系
-》默認調用父類的構造方法
-》使用base可以指定調用父類構造方法
靜態構造方法
靜態構造方法從程序的開始到結束只會被調用執行一次,當new對象或者訪問這個類的字段或屬性等時就會調用執行,
多態實現的前提:
-》繼承
-》子類父類方法名必須相同
裡氏轉換原則(只是實現多態的一個條件不是前提)
-》父類 父類對象=new 子類();
。。。
子類 子類對象=(子類)父類對象 必須滿足上面的條件這裡才能轉換成功
隱藏基類的方式
只需要在子類的方法前寫上new關鍵字即可(不寫也可以,系統會自動添加)
隱藏看類型
class Person { public void SayHello() { Console.WriteLine("依依呀呀"); } } class American : Person { public new void SayHello() { Console.WriteLine("Hello"); } } class Korean : Person { public new void SayHello() { Console.WriteLine("啊你喲哈撒喲"); } }
重寫基類方法
-》在父類方法前加上virtual
-》在子類方法前加上override
重寫只管新
class Person { public virtual void SayHello() { Console.WriteLine("依依呀呀"); } } class American : Person { public override void SayHello() { Console.WriteLine("Hello"); } } class Korean : Person { public override void SayHello() { Console.WriteLine("啊你喲哈撒喲"); } }
二、產生隨機數
Random:專門處理隨機數的類。(偽隨機數,其運行原理是:先得到系統的當前時間(精確到毫秒),然後根據系統的當前時間計算出一個數(就是所謂的偽隨機數))
--》創建隨機對象
Random r=nrw Radom();
注意: 隨機數的對象不要創建在循環裡 不然會得到一些重復一樣的數字
-->調用Next方法的得到隨機數
-》next方法有三個重載
int res=r.netx(); 產生一個非負數的隨機數
int res=r.next(100); 產生一個0到99的隨機數,兩端可以取到
int res=r.next(2,30);產生一個2到29的隨機數,兩端可以取到
記錄時間的類
Stopwath:
Stopwath stop=new Stopwath();
stop.start(); 開始計算
.....
stop.Stop(); 停止計算
console.writeLine(stop.Elapsed); 得到計算結果
多態:為了程序的可擴展性
-》開放封閉的原則(對擴展開放,對修改封閉)
多態的使用:
將不同的對象都當做父類來看,屏蔽掉各個對象間的不同,寫出通用代碼,做出通用編程,
三、抽象類
什麼是抽象方法
有些時候父類的方法不需要實現
有些時候不知道怎麼實現
沒有方法體的方法叫做抽象方法,使用abstact修飾,
包含抽象方法的類,也必須是一個抽象類。
抽象類中可以包含非抽象成員
抽象方法的用法和虛方法的用法完全一樣
不同的是他們的定義不一樣,抽象類不可以實例化
抽象類存在就是為了被繼承的,因此不允許定義為private.
抽象類不能實例化,比一般類多一抽象成員
抽象類與一般類有兩個最大的區別
--》不能實例化
--》 具有抽象成員 ( 凡是跟方法有關的都可以抽象)
-》方法
-》屬性
-》索引器(帶參數的屬性)
-》事件的聲明(可以看做“屬性”,屬性石一個get set方法,事件是add remove方法)
使用抽象屬性的時候,一般是抽象類提供屬性以及可訪問性
子類提供字段與屬性的實現
public abstract string s
{
get; //這裡的屬性和自動屬性長得很像,但是要注意他們的含義不一樣,這裡由abstract修飾就是告訴系統,這裡是抽象方法沒有方法體,所以這裡不用寫{}
set; //抽象屬性可以只有get或set,因為他可以由構造方法給字段賦值,而自動屬性是後台自動生成字段,所以自動屬性的get set要成對出現
}
四、重寫ToString方法
string[] str = { "1", "2", "3", "4" }; MyClass myClass = new MyClass(); myClass.Name1 = "我是MyClass"; myClass.Name2 = "0"; myClass.Name3 = "3"; myClass.Name4 = "4"; myClass.Name5 = "5"; MyStruct myStruct; myStruct.Name = "我是MyStruct"; Console.WriteLine(str); Console.WriteLine(myClass); Console.WriteLine(myStruct);
這裡打印數組和類系統會默認調用ToString()方法 任何類型都有一個ToString()方法,因為這個方法是object根類提供的,C#裡所有的類都繼承自object類,所以object的ToString()會被繼承下來。
Reflector可以看到object的ToString()方法是個虛方法,如果子類沒有重寫,那麼系統都會默認調用這個方法,
可以看到這個方法調用 this.GetType()方法 (獲得當前實力的命名空間),然後返回
所以上面打印出來的是這個實例所在的命名空間名和實例名。
public virtual string ToString() { return this.GetType().ToString(); }
既然父類提供的是虛方法那子類就可以重寫,我們可以通過子類重寫ToString()方法來實現我們想要顯示的內容
class MyClass { public string name1; public override string ToString() { return name1; } } class Program { static void Main(string[] args) { MyClass myClass = new MyClass(); myClass.name1 = "張三"; Console.WriteLine(myClass);//這裡會顯示 張三 Console.ReadKey(); } }
//本系列會持續更新。晚安!