国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發(fā) > 綜合 > 正文

C#體驗(yàn)編程技術(shù) 類與對象

2024-07-21 02:24:45
字體:
供稿:網(wǎng)友
  組件編程不是對傳統(tǒng)面向?qū)ο蟮膾仐墸喾唇M件編程正是面向?qū)ο缶幊痰纳罨桶l(fā)展。類作為面向?qū)ο蟮撵`魂在c#語言里有著相當(dāng)廣泛深入的應(yīng)用,很多非常“sharp”的組件特性甚至都是直接由類包裝而成。對類的深度掌握自然是我們“sharp xp”重要的一環(huán)。

  c#的類是一種對包括數(shù)據(jù)成員,函數(shù)成員和嵌套類型進(jìn)行封裝的數(shù)據(jù)結(jié)構(gòu)。其中數(shù)據(jù)成員可以是常量,域。函數(shù)成員可以是方法,屬性,索引器,事件,操作符,實(shí)例構(gòu)建器,靜態(tài)構(gòu)建器,析構(gòu)器。我們將在“第五講 構(gòu)造器與析構(gòu)器”和“第六講 域 方法 屬性與索引器”對這些成員及其特性作詳細(xì)的剖析。除了某些導(dǎo)入的外部方法,類及其成員在c#中的聲明和實(shí)現(xiàn)通常要放在一起。

  c#用多種修飾符來表達(dá)類的不同性質(zhì)。根據(jù)其保護(hù)級c#的類有五種不同的限制修飾符:

  1. public可以被任意存取;
  2. protected只可以被本類和其繼承子類存取;
  3. internal只可以被本組合體(assembly)內(nèi)所有的類存取,組合體是c#語言中類被組合后的邏輯單位和物理單位,其編譯后的文件擴(kuò)展名往往是“.dll”或“.exe”。
  4. protected internal唯一的一種組合限制修飾符,它只可以被本組合體內(nèi)所有的類和這些類的繼承子類所存取。
  5. private只可以被本類所存取。

  如果不是嵌套的類,命名空間或編譯單元內(nèi)的類只有public和internal兩種修飾。

  new修飾符只能用于嵌套的類,表示對繼承父類同名類型的隱藏。

  abstract用來修飾抽象類,表示該類只能作為父類被用于繼承,而不能進(jìn)行對象實(shí)例化。抽象類可以包含抽象的成員,但這并非必須。abstract不能和new同時(shí)用。下面是抽象類用法的偽碼:

abstract class a{   public abstract void f();}abstract class b: a{   public void g() {}}class c: b{   public override void f()    {//方法f的實(shí)現(xiàn)  }}

  抽象類a內(nèi)含一個(gè)抽象方法f(),它不能被實(shí)例化。類b繼承自類a,其內(nèi)包含了一個(gè)實(shí)例方法g(),但并沒有實(shí)現(xiàn)抽象方法f(),所以仍然必須聲明為抽象類。類c繼承自類b,實(shí)現(xiàn)類抽象方法f(),于是可以進(jìn)行對象實(shí)例化。

  sealed用來修飾類為密封類,阻止該類被繼承。同時(shí)對一個(gè)類作abstract和sealed的修飾是沒有意義的,也是被禁止的。

對象與this關(guān)鍵字

  類與對象的區(qū)分對我們把握oo編程至關(guān)重要。我們說類是對其成員的一種封裝,但類的封裝設(shè)計(jì)僅僅是我們編程的第一步,對類進(jìn)行對象實(shí)例化,并在其數(shù)據(jù)成員上實(shí)施操作才是我們完成現(xiàn)實(shí)任務(wù)的根本。實(shí)例化對象采用myclass myobject=new myclass()語法,這里的new語義將調(diào)用相應(yīng)的構(gòu)建器。c#所有的對象都將創(chuàng)建在托管堆上。實(shí)例化后的類型我們稱之為對象,其核心特征便是擁有了一份自己特有的數(shù)據(jù)成員拷貝。這些為特有的對象所持有的數(shù)據(jù)成員我們稱之為實(shí)例成員。相反那些不為特有的對象所持有的數(shù)據(jù)成員我們稱之為靜態(tài)成員,在類中用static修飾符聲明。僅對靜態(tài)數(shù)據(jù)成員實(shí)施操作的稱為靜態(tài)函數(shù)成員。c#中靜態(tài)數(shù)據(jù)成員和函數(shù)成員只能通過類名引用獲取,看下面的代碼:

using system;class a{public int count;public void f(){console.writeline(this.count);}public static string name;public static void g(){console.writeline(name);}}class test{public static void main(){a a1=new a();a a2=new a();a1.f();a1.count=1;a2.f();a2.count=2;a.name="ccw";a.g();}}

  我們聲明了兩個(gè)a對象a1,a2。對于實(shí)例成員count和f(),我們只能通過a1,a2引用。對于靜態(tài)成員name和g()我們只能通過類型a來引用,而不可以這樣a1.name,或a1.g()。

  在上面的程序中,我們看到在實(shí)例方法f()中我們才用this來引用變量count。這里的this是什么意思呢?this 關(guān)鍵字引用當(dāng)前對象實(shí)例的成員。在實(shí)例方法體內(nèi)我們也可以省略this,直接引用count,實(shí)際上兩者的語義相同。理所當(dāng)然的,靜態(tài)成員函數(shù)沒有 this 指針。this 關(guān)鍵字一般用于從構(gòu)造函數(shù)、實(shí)例方法和實(shí)例訪問器中訪問成員。

在構(gòu)造函數(shù)中this用于限定被相同的名稱隱藏的成員,例如:

class employee{public employee(string name, string alias) {   this.name = name;   this.alias = alias;}}

  將對象作為參數(shù)傳遞到其他方法時(shí)也要用this表達(dá),例如:

calctax(this);

  聲明索引器時(shí)this更是不可或缺,例如:

public int this [int param]{      get      {         return array[param];      }      set      {         array[param] = value;      }}

system.object類

  c#中所有的類都直接或間接繼承自system.object類,這使得c#中的類得以單根繼承。如果我們沒有明確指定繼承類,編譯器缺省認(rèn)為該類繼承自system.object類。system.object類也可用小寫的object關(guān)鍵字表示,兩者完全等同。自然c#中所有的類都繼承了system.object類的公共接口,剖析它們對我們理解并掌握c#中類的行為非常重要。下面是僅用接口形式表示的system.object類:

namespace system{public class object{public static bool equals(object obja,object objb){}public static bool referenceequals(object obja,object objb){}public object(){}public virtual bool equals(object obj){}public virtual int gethashcode(){}public type gettype(){}public virtual string tostring(){}protected virtual void finalize(){}protected object memberwiseclone(){}}

  我們先看object的兩個(gè)靜態(tài)方法equals(object obja,object objb),referenceequals(object obja,object objb)和一個(gè)實(shí)例方法equals(object obj)。在我們闡述這兩個(gè)方法之前我們首先要清楚面向?qū)ο缶幊虄蓚€(gè)重要的相等概念:值相等和引用相等。值相等的意思是它們的數(shù)據(jù)成員按內(nèi)存位分別相等。引用相等則是指它們指向同一個(gè)內(nèi)存地址,或者說它們的對象句柄相等。引用相等必然推出值相等。對于值類型關(guān)系等號“= =”判斷兩者是否值相等(結(jié)構(gòu)類型和枚舉類型沒有定義關(guān)系等號“= =”,我們必須自己定義)。對于引用類型關(guān)系等號“= =”判斷兩者是否引用相等。值類型在c#里通常沒有引用相等的表示,只有在非托管編程中采用取地址符“&”來間接判斷二者的地址是否相等。

  靜態(tài)方法equals(object obja,object objb)首先檢查兩個(gè)對象obja和objb是否都為null,如果是則返回true,否則進(jìn)行obja.equals(objb)調(diào)用并返回其值。問題歸結(jié)到實(shí)例方法equals(object obj)。該方法缺省的實(shí)現(xiàn)其實(shí)就是{return this= =obj;}也就是判斷兩個(gè)對象是否引用相等。但我們注意到該方法是一個(gè)虛方法,c#推薦我們重寫此方法來判斷兩個(gè)對象是否值相等。實(shí)際上microsoft.net框架類庫內(nèi)提供的許多類型都重寫了該方法,如:system.string(string),system.int32(int)等,但也有些類型并沒有重寫該方法如:system.array等,我們在使用時(shí)一定要注意。對于引用類型,如果沒有重寫實(shí)例方法equals(object obj),我們對它的調(diào)用相當(dāng)于this= =obj,即引用相等判斷。所有的值類型(隱含繼承自system.valuetype類)都重寫了實(shí)例方法equals(object obj)來判斷是否值相等。

  注意對于對象x,x.equals(null)返回false,這里x顯然不能為null(否則不能完成equals()調(diào)用,系統(tǒng)拋出空引用錯(cuò)誤)。從這里我們也可看出設(shè)計(jì)靜態(tài)方法equals(object obja,object objb)的原因了--如果兩個(gè)對象obja和objb都可能為null,我們便只能用object. equals(object obja,object objb)來判斷它們是否值相等了--當(dāng)然如果我們沒有改寫實(shí)例方法equals(object obj),我們得到的仍是引用相等的結(jié)果。我們可以實(shí)現(xiàn)接口icomparable(有關(guān)接口我們將在“第七講 接口 繼承與多態(tài)”里闡述)來強(qiáng)制改寫實(shí)例方法equals(object obj)。

  對于值類型,實(shí)例方法equals(object obj)應(yīng)該和關(guān)系等號“= =”的返回值一致,也就是說如果我們重寫了實(shí)例方法equals(object obj),我們也應(yīng)該重載或定義關(guān)系等號“= =”操作符,反之亦然。雖然值類型(繼承自system.valuetype類)都重寫了實(shí)例方法equals(object obj),但c#推薦我們重寫自己的值類型的實(shí)例方法equals(object obj),因?yàn)橄到y(tǒng)的system.valuetype類重寫的很低效。對于引用類型我們應(yīng)該重寫實(shí)例方法equals(object obj)來表達(dá)值相等,一般不應(yīng)該重載關(guān)系等號“= =”操作符,因?yàn)樗娜笔≌Z義是判斷引用相等。

  靜態(tài)方法referenceequals(object obja,object objb)判斷兩個(gè)對象是否引用相等。如果兩個(gè)對象為引用類型,那么它的語義和沒有重載的關(guān)系等號“= =”操作符相同。如果兩個(gè)對象為值類型,那么它的返回值一定是false。

  實(shí)例方法gethashcode()為相應(yīng)的類型提供哈希(hash)碼值,應(yīng)用于哈希算法或哈希表中。需要注意的是如果我們重寫了某類型的實(shí)例方法equals(object obj),我們也應(yīng)該重寫實(shí)例方法gethashcode()--這理所應(yīng)當(dāng),兩個(gè)對象的值相等,它們的哈希碼也應(yīng)該相等。下面的代碼是對前面幾個(gè)方法的一個(gè)很好的示例:

using system;struct a{public int count;}class b{public int number;}class c{public int integer=0;public override bool equals(object obj){c c=obj as c;if (c!=null)return this.integer==c.integer;elsereturn false;}public override int gethashcode(){return 2^integer;}}class test{public static void main(){a a1,a2;a1.count=10;a2=a1;//console.write(a1==a2);沒有定義“= =”操作符console.write(a1.equals(a2));//trueconsole.writeline(object.referenceequals(a1,a2));//falseb b1=new b();b b2=new b();b1.number=10;b2.number=10;console.write(b1==b2);//falseconsole.write(b1.equals(b2));//falseconsole.writeline(object.referenceequals(b1,b2));//falseb2=b1;console.write(b1==b2);//trueconsole.write(b1.equals(b2));//trueconsole.writeline(object.referenceequals(b1,b2));//truec c1=new c();c c2=new c();c1.integer=10;c2.integer=10;console.write(c1==c2);//falseconsole.write(c1.equals(c2));//trueconsole.writeline(object.referenceequals(c1,c2));//falsec2=c1;console.write(c1==c2);//trueconsole.write(c1.equals(c2));//trueconsole.writeline(object.referenceequals(c1,c2));//true}}

  如我們所期望,編譯程序并運(yùn)行我們會(huì)得到以下輸出:

    truefalse
    falsefalsefalse
    truetruetrue
    falsetruefalse
    truetruetrue

  實(shí)例方法gettype()與typeof的語義相同,它們都通過查詢對象的元數(shù)據(jù)來確定對象的運(yùn)行時(shí)類型,我們在“第十講 特征與映射”對此作詳細(xì)的闡述。

  實(shí)例方法tostring()返回對象的字符串表達(dá)形式。如果我們沒有重寫該方法,系統(tǒng)一般將類型名作為字符串返回。

  受保護(hù)的finalize()方法在c#中有特殊的語義,我們將在“第五講 構(gòu)造器與析構(gòu)器”里詳細(xì)闡述。

  受保護(hù)的memberwiseclone()方法返回目前對象的一個(gè)“影子拷貝”,該方法不能被子類重寫。“影子拷貝”僅僅是對象的一份按位拷貝,其含義是對對象內(nèi)的值類型變量進(jìn)行賦值拷貝,對其內(nèi)的引用類型變量進(jìn)行句柄拷貝,也就是拷貝后的引用變量將持有對同一塊內(nèi)存的引用。相對于“影子拷貝”的是深度拷貝,它對引用類型的變量進(jìn)行的是值復(fù)制,而非句柄復(fù)制。例如x是一個(gè)含有對象a,b引用的對象,而對象a又含有對象m的引用。y是x的一個(gè)“影子拷貝”。那么y將擁有同樣的a,b的引用。但對于x的一個(gè)“深度拷貝”z來說,它將擁有對象c和d的引用,以及一個(gè)間接的對象n的引用,其中c是a的一份拷貝,d是b的一份拷貝,n是m的一份拷貝。深度拷貝在c#里通過實(shí)現(xiàn)icloneable接口(提供clone()方法)來完成。

  對對象和system.object的把握為類的學(xué)習(xí)作了一個(gè)很好的鋪墊,但這僅僅是我們銳利之行的一小步,關(guān)乎對象成員初始化,內(nèi)存引用的釋放,繼承與多態(tài),異常處理等等諸多“sharp”特技堪為浩瀚,讓我們繼續(xù)期待下面的專題!

發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 白玉县| 佛坪县| 济阳县| 彭州市| 宣汉县| 明星| 涟水县| 沂水县| 密云县| 河曲县| 柳林县| 德惠市| 延津县| 北宁市| 富蕴县| 高雄县| 电白县| 通化县| 齐齐哈尔市| 云龙县| 滁州市| 周至县| 班玛县| 新干县| 汕尾市| 博客| 汨罗市| 微山县| 金平| 洞头县| 唐河县| 临沂市| 舟山市| 营口市| 昌吉市| 大足县| 承德县| 栖霞市| 五华县| 中牟县| 林州市|