面向對象多態
一、裝箱和拆箱
裝箱:將值類型轉換為引用類型。object o = 1;值類型給引用類型賦值
拆箱:將引用類型轉換為值類型。int n = (int)o; 強制轉換為值類型
滿足條件:兩種類型是否存在繼承關系。
int n = Convert.ToInt32("12"); 未發生裝箱或拆箱 。int存儲在棧,string存儲在堆
裝箱或拆箱會影響程序運行事件。
二、面向對象多態
對象在調用同一個方法的時候表現出來多種狀態。
1、虛方法
將父類的方法標記為虛方法使用關鍵字virtual,可以被子類重新寫一遍
PRotected void Page_Load(object sender, EventArgs e){ person[] p = new person[2]; chinese p1 = new chinese(); jpan p2 = new jpan(); p[0] = p1; p[1] = p2; Response.Write(p[0].SayHi()); //調用的方法時取決于自己是什么對象 Response.Write(p[1].SayHi());}public class person{ public virtual string SayHi() //父類方法使用virtual表示該方法是虛方法 { return "人類"; }}public class chinese : person{ public override string SayHi() //子類方法使用override表示該方法是重寫虛方法 { return "中國人"; }}public class jpan : person{ public override string SayHi() // override { return "日本人"; }}
2、抽象類
當父類中的方法不知道如何去實現的時候,可以考略將父類寫成抽象類,將方法寫成抽象方法。
使用abstract定義的類為抽象類,使用abstract定義的方法為抽象方法,抽象函數是沒有方法體的。
抽象類無法實例化父類,直接實例化子類調用。
父類方法中有意義時使用虛方法,父類方法中方法無意義時使用抽象類。
protected void Page_Load(object sender, EventArgs e){ //抽象類不能被實例化 只能實例化子類對象 xingzhuang y = new yuan(5); double mianji = y.mianji(); double zhouchang = y.zhouchang(); Response.Write("半徑為5的原型面積為:" + mianji + ",周長:" + zhouchang); xingzhuang ju = new juxing(10, 20); double mianji1 = ju.mianji(); double zhouchang1 = ju.zhouchang(); Response.Write("高為10的寬為20的矩形面積為:" + mianji1 + ",周長:" + zhouchang1);}public abstract class xingzhuang //被標記為abstract的類稱為抽象類{ public string Name { get; set; } //抽象類中可以包含實例成員,并且實力成員可以不被子類實現。 public abstract double mianji(); //抽象方法必須標記為abstract,并且不能有任何實現,必須在抽象類中。 public abstract double zhouchang(); //抽象成員的訪問修飾符不能是private}public class yuan : xingzhuang{ public double R { get; set; } public yuan(double r) { this.R = r; } public override double mianji() //子類繼承抽象類后必須把父類中所有抽象成員重寫 { return Math.PI * this.R * this.R; } public override double zhouchang() //子類繼承抽象類后必須把父類中所有抽象成員重寫 { return 2 * Math.PI * this.R; }}public class juxing : xingzhuang{ public double width { get; set; } public double height { get; set; } public juxing(double height, double width) { this.height = height; this.width = width; } public override double mianji() //子類繼承抽象類后必須把父類中所有抽象成員重寫 { return this.height * this.width; } public override double zhouchang() //子類繼承抽象類后必須把父類中所有抽象成員重寫 { return (this.height + this.width) * 2; }}
三、簡單工廠設計模式
class Program{ static void Main(string[] args) { while (true) { Console.WriteLine("請輸入要進入的磁盤"); string path = Console.ReadLine(); Console.WriteLine("請輸入要進入的文件"); string fileName = Console.ReadLine(); FileFather f = getFile(fileName, path + fileName); f.OpenFile(); //打開一個文件取決于輸入一個什么文件 Console.ReadKey(); } } public static FileFather getFile(string fileName, string fullName) //簡單工廠形式返回父類 { string ext = Path.GetExtension(fileName); FileFather f; switch (ext) { case ".txt": f = new txtPath(fullName); break; case ".jpg": f = new jpgPath(fullName); break; default: f = null; break; } return f; }}public abstract class FileFather //抽象父類{ public string fileName { get; set; } //文件全路徑 public FileFather(string fileName) //構造函數 自己不能用 { this.fileName = fileName; } public abstract void OpenFile(); //抽象方法}public class txtPath : FileFather{ public txtPath(string fileName) //繼承父類構造函數 : base(fileName) { } public override void OpenFile() //子類重寫 { ProcessStartInfo psi = new ProcessStartInfo(fileName);//使用進程打開指定文件 Process pro = new Process(); pro.StartInfo = psi; pro.Start(); }}public class jpgPath : FileFather{ public jpgPath(string fileName) : base(fileName) { } public override void OpenFile() { ProcessStartInfo psi = new ProcessStartInfo(fileName); Process pro = new Process(); pro.StartInfo = psi; pro.Start(); }}
四、值傳遞和引用傳遞
值類型:int double char decimal bool enum struct 存儲于棧
引用類型:string 數組 自定義類 集合 object 接口 存儲于堆
值傳遞:int n1 = 10; n2 = n1; n2 = 20; 值類型在賦值的時候,傳遞的是這個值的本身,復制了一份。 p1 = 10 ; p2 = 20;
引用傳遞:p1.name = "3"; p2.name = p1.name; p2.name="4"; 引用類型在賦值的時候,傳遞的是這個值的引用,引用同一份,p1 p2 指向同一塊內存。
五、序列化和反序列化
序列化:將對象轉換為二進制
反序列化:將二進制轉換為對象
作用:傳輸數據。
1、將這個類標記為可以被序列化 [Serializable]。
2、使用BinaryFormatter開始序列化對象。
protected void Page_Load(object sender, EventArgs e){ //將P傳輸給對方電腦 person p = new person(); p.name = "張三"; p.age = 18; p.gender = '男'; using (FileStream sw = new FileStream(@"d:/11.txt", FileMode.OpenOrCreate, Fileaccess.ReadWrite))//序列化到目標文件 { //開始序列化對象 BinaryFormatter bf = new BinaryFormatter(); bf.Serialize(sw, p); //要被序列化的對象 sw.Write 自動完成 } person per = new person(); //接收對方發過來的二進制 反序列化對象 using (FileStream sr = new FileStream(@"d:/11.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite)) { BinaryFormatter bf1 = new BinaryFormatter(); per = (person)bf1.Deserialize(sr); } Response.Write(per.name + per.age + per.gender);}[Serializable] //將這個類標記為可被序列化public class person{ public string name { get; set; } public int age { get; set; } public char gender { get; set; }}
六、部分類partial
局部類型允許我們將一個類、接口或結構分成好幾個部分,分別實現在幾個不同的.cs文件中
public partial class person
{
}
public partial class person
{
}
1)類型特別大,不宜放在一個文件中實現。
2)需要多人合作編寫一個類。
七、密封類sealed
密封類用sealed修飾,不能被繼承。因此,它也不能是抽象類。
重寫ToString()
子類重寫父類的虛方法
public override string ToString(){ return "sd";}
八、接口interface
接口是一種規范,是一個引用類型,因為繼承只能繼承一個,所以通過接口可以實現多重繼承。
只要一個類繼承了一個接口,這個類就必須實現接口的所有成員。
接口不能實例化,不能被new。
在聲明接口成員的時候,不準為接口成員編寫具體的可執行代碼.
接口與接口之間可以繼承,可以多繼承,接口不能繼承類。
接口成員不能有static、abstract、override、virtual修飾符,使用new修飾符不會報錯,但會給出警告說不需要關鍵字new。
一個類繼承了接口又繼承了類,語法上必須先繼承類,再繼承接口
public interface IFly{ //成員不允許添加訪問修飾符,默認就是public string name { get; set; } //接口可以有方法、屬性、所引器。 void Fly(); //不可以有方法體}public class father{}public class person : father, IFly //先寫類 后寫接口{ public string name { get; set; } public void Fly() { }}
顯示接口
//用來解決方法重名問題class Program{ static void Main(string[] args) { Ifly fly = new Birad(); fly.Fly(); //接口的 Briad bid = new Briad(); bid.Fly(); //自己的 }}public class Birad : Ifly //鳥類繼承接口ifly{ public string Fly() //類自己的方法 { return "fly"; } public string Ifly.Fly() { //接口的方法 return "ifly11111"; }}public interface Ifly //定義接口 fly方法{ string Fly();}
九、異常與異常處理
try{ int number = 10; //可能出錯的代碼塊}catch (Exception ex){ Console.WriteLine(ex.Message);//錯誤信息 throw new Exception("錯誤"); //拋出異常}
1、什么時候用虛方法實現多態?
可以提取出一個父類,需要寫出明方法時。
2、什么時候用抽象類實現多態?
可以提取出一個父類,但是不知道具體怎么實現時。
3、什么時候用接口來實現多態?
無法提取出一個父類,但是都有一個共同的行為,或者需要多重繼承時。
新聞熱點
疑難解答