講解C#面相對(duì)象編程中的類(lèi)與對(duì)象的特性與概念
類(lèi)
“類(lèi)”是一種構(gòu)造,通過(guò)使用該構(gòu)造,您可以將其他類(lèi)型的變量、方法和事件組合在一起,從而創(chuàng)建自己的自定義類(lèi)型。類(lèi)就像一個(gè)藍(lán)圖,它定義類(lèi)型的數(shù)據(jù)和行為。如果類(lèi)沒(méi)有聲明為靜態(tài)類(lèi),客戶(hù)端代碼就可以創(chuàng)建賦給變量的“對(duì)象”或“實(shí)例”,從而使用該類(lèi)。在對(duì)變量的所有引用都超出范圍之前,該變量始終保持在內(nèi)存中。所有引用都超出范圍時(shí),CLR 將標(biāo)記該變量以供垃圾回收。如果類(lèi)聲明為靜態(tài)類(lèi),則內(nèi)存中只存在一個(gè)副本,并且客戶(hù)端代碼只能通過(guò)該類(lèi)自身而不是“實(shí)例變量”訪(fǎng)問(wèn)該類(lèi)。
聲明類(lèi)
類(lèi)使用 class 關(guān)鍵字進(jìn)行聲明,如下面的示例所示:
public class Customer { //Fields, properties, methods and events go here... }
class 關(guān)鍵字前面是訪(fǎng)問(wèn)級(jí)別。由于在該例中使用 public,因此任何人都可以基于該類(lèi)創(chuàng)建對(duì)象。類(lèi)的名稱(chēng)位于 class 關(guān)鍵字的后面。定義的其余部分是類(lèi)的主體,用于定義行為和數(shù)據(jù)。類(lèi)的字段、屬性、方法和事件統(tǒng)稱(chēng)為“類(lèi)成員”。
創(chuàng)建對(duì)象
盡管有時(shí)類(lèi)和對(duì)象可互換,但它們是不同的概念。類(lèi)定義對(duì)象的類(lèi)型,但它不是對(duì)象本身。對(duì)象是基于類(lèi)的具體實(shí)體,有時(shí)稱(chēng)為類(lèi)的實(shí)例。
通過(guò)使用 new 關(guān)鍵字(后跟對(duì)象將基于的類(lèi)的名稱(chēng))可以創(chuàng)建對(duì)象,如下所示:
Customer object1 = new Customer();
創(chuàng)建類(lèi)的實(shí)例后,將向程序員傳遞回對(duì)該對(duì)象的引用。在前面的示例中,object1 是對(duì)基于 Customer 的對(duì)象的引用。此引用引用新對(duì)象,但不包含對(duì)象數(shù)據(jù)本身。實(shí)際上,可以在根本不創(chuàng)建對(duì)象的情況下創(chuàng)建對(duì)象引用:
Customer object2;
建議不要?jiǎng)?chuàng)建像這樣的不引用對(duì)象的對(duì)象引用,因?yàn)樵谶\(yùn)行時(shí)通過(guò)這樣的引用來(lái)訪(fǎng)問(wèn)對(duì)象的嘗試將會(huì)失敗。但是,可以創(chuàng)建這樣的引用來(lái)引用對(duì)象,方法是創(chuàng)建新對(duì)象,或者將它分配給現(xiàn)有的對(duì)象,如下所示:
Customer object3 = new Customer(); Customer object4 = object3;
此代碼創(chuàng)建了兩個(gè)對(duì)象引用,它們引用同一個(gè)對(duì)象。因此,通過(guò) object3 對(duì)對(duì)象所做的任何更改都將反映在隨后使用的 object4 中。由于基于類(lèi)的對(duì)象是按引用來(lái)引用的,因此類(lèi)稱(chēng)為引用類(lèi)型。
類(lèi)繼承
繼承是通過(guò)使用“派生”來(lái)實(shí)現(xiàn)的,而派生意味著類(lèi)是使用“基類(lèi)”聲明的,它的數(shù)據(jù)和行為從基類(lèi)繼承。通過(guò)在派生的類(lèi)名后面追加冒號(hào)和基類(lèi)名稱(chēng),可以指定基類(lèi),如下所示:
public class Manager : Employee { // Employee fields, properties, methods and events are inherited // New Manager fields, properties, methods and events go here... }
當(dāng)類(lèi)聲明基類(lèi)時(shí),它繼承基類(lèi)除構(gòu)造函數(shù)以外的所有成員。
與 C++ 不同,C# 中的類(lèi)只能直接從一個(gè)基類(lèi)繼承。但是,因?yàn)榛?lèi)自身也可能繼承自另一個(gè)類(lèi),所以類(lèi)可以間接繼承多個(gè)基類(lèi)。而且,一個(gè)類(lèi)可以直接實(shí)現(xiàn)一個(gè)以上的接口。
類(lèi)可以聲明為抽象類(lèi)。抽象類(lèi)包含具有簽名定義但沒(méi)有實(shí)現(xiàn)的抽象方法。抽象類(lèi)不能進(jìn)行實(shí)例化。只能通過(guò)實(shí)現(xiàn)抽象方法的派生類(lèi)使用抽象類(lèi)。相比之下,密封類(lèi)不允許其他類(lèi)從其派生。
類(lèi)定義可在不同的源文件之間進(jìn)行拆分。
描述
下面的示例中定義了一個(gè)公共類(lèi),其中包含一個(gè)字段、一個(gè)方法和一個(gè)稱(chēng)為構(gòu)造函數(shù)的特殊方法。有關(guān)更多信息,請(qǐng)參見(jiàn)構(gòu)造函數(shù)(C# 編程指南)。然后使用 new 關(guān)鍵字將該類(lèi)實(shí)例化。
public class Person { // Field public string name; // Constructor that takes no arguments. public Person() { name = "unknown"; } // Constructor that takes one argument. public Person(string nm) { name = nm; } // Method public void SetName(string newName) { name = newName; } } class TestPerson { static void Main() { // Call the constructor that has no parameters. Person person1 = new Person(); Console.WriteLine(person1.name); person1.SetName("John Smith"); Console.WriteLine(person1.name); // Call the constructor that has one parameter. Person person2 = new Person("Sarah Jones"); Console.WriteLine(person2.name); // Keep the console window open in debug mode. Console.WriteLine("Press any key to exit."); Console.ReadKey(); } }
輸出:
unknown John Smith Sarah Jones
對(duì)象
類(lèi)或結(jié)構(gòu)定義的作用類(lèi)似于藍(lán)圖,指定該類(lèi)型可以進(jìn)行哪些操作。從本質(zhì)上說(shuō),對(duì)象是按照此藍(lán)圖分配和配置的內(nèi)存塊。程序可以創(chuàng)建同一個(gè)類(lèi)的多個(gè)對(duì)象。對(duì)象也稱(chēng)為實(shí)例,可以存儲(chǔ)在命名變量中,也可以存儲(chǔ)在數(shù)組或集合中。使用這些變量來(lái)調(diào)用對(duì)象方法及訪(fǎng)問(wèn)對(duì)象公共屬性的代碼稱(chēng)為客戶(hù)端代碼。在 C# 等面向?qū)ο蟮恼Z(yǔ)言中,典型的程序由動(dòng)態(tài)交互的多個(gè)對(duì)象組成。
結(jié)構(gòu)實(shí)例。. 選件類(lèi)實(shí)例
由于類(lèi)是引用類(lèi)型,因此類(lèi)對(duì)象的變量引用該對(duì)象在托管堆上的地址。如果將同一類(lèi)型的第二個(gè)對(duì)象分配給第一個(gè)對(duì)象,則兩個(gè)變量都引用該地址的對(duì)象。這一點(diǎn)將在本主題后面部分進(jìn)行更詳細(xì)的討論。
類(lèi)的實(shí)例是使用 new 運(yùn)算符創(chuàng)建的。在下面的示例中,Person 為類(lèi)型,person1 和 person 2 為該類(lèi)型的實(shí)例(即對(duì)象)。
public class Person { public string Name { get; set; } public int Age { get; set; } public Person(string name, int age) { Name = name; Age = age; } //Other properties, methods, events... } class Program { static void Main() { Person person1 = new Person("Leopold", 6); Console.WriteLine("person1 Name = {0} Age = {1}", person1.Name, person1.Age); // Declare new person, assign person1 to it. Person person2 = person1; //Change the name of person2, and person1 also changes. person2.Name = "Molly"; person2.Age = 16; Console.WriteLine("person2 Name = {0} Age = {1}", person2.Name, person2.Age); Console.WriteLine("person1 Name = {0} Age = {1}", person1.Name, person1.Age); // Keep the console open in debug mode. Console.WriteLine("Press any key to exit."); Console.ReadKey(); } }
輸出:
person1 Name = Leopold Age = 6 person2 Name = Molly Age = 16 person1 Name = Molly Age = 16
由于結(jié)構(gòu)是值類(lèi)型,因此結(jié)構(gòu)對(duì)象的變量具有整個(gè)對(duì)象的副本。結(jié)構(gòu)的實(shí)例也可以使用 new 運(yùn)算符來(lái)創(chuàng)建,但這不是必需的,如下面的示例所示:
public struct Person { public string Name; public int Age; public Person(string name, int age) { Name = name; Age = age; } } public class Application { static void Main() { // Create struct instance and initialize by using "new". // Memory is allocated on thread stack. Person p1 = new Person("Alex", 9); Console.WriteLine("p1 Name = {0} Age = {1}", p1.Name, p1.Age); // Create new struct object. Note that struct can be initialized // without using "new". Person p2 = p1; // Assign values to p2 members. p2.Name = "Spencer"; p2.Age = 7; Console.WriteLine("p2 Name = {0} Age = {1}", p2.Name, p2.Age); // p1 values remain unchanged because p2 is copy. Console.WriteLine("p1 Name = {0} Age = {1}", p1.Name, p1.Age); // Keep the console open in debug mode. Console.WriteLine("Press any key to exit."); Console.ReadKey(); } }
輸出:
p1 Name = Alex Age = 9 p2 Name = Spencer Age = 7 p1 Name = Alex Age = 9
p1 和 p2 的內(nèi)存在線(xiàn)程堆棧上進(jìn)行分配。該內(nèi)存隨聲明它的類(lèi)型或方法一起回收。這就是在賦值時(shí)復(fù)制結(jié)構(gòu)的一個(gè)原因。相比之下,當(dāng)對(duì)類(lèi)實(shí)例對(duì)象的所有引用都超出范圍時(shí),為該類(lèi)實(shí)例分配的內(nèi)存將由公共語(yǔ)言運(yùn)行時(shí)自動(dòng)回收(垃圾回收)。無(wú)法像在 C++ 中那樣明確地銷(xiāo)毀類(lèi)對(duì)象。
對(duì)象標(biāo)識(shí)與. 值相等性
在比較兩個(gè)對(duì)象是否相等時(shí),首先必須明確您是想知道兩個(gè)變量是否表示內(nèi)存中的同一對(duì)象,還是想知道這兩個(gè)對(duì)象的一個(gè)或多個(gè)字段的值是否相等。如果您要對(duì)值進(jìn)行比較,則必須考慮這兩個(gè)對(duì)象是值類(lèi)型(結(jié)構(gòu))的實(shí)例,還是引用類(lèi)型(類(lèi)、委托、數(shù)組)的實(shí)例。
若要確定兩個(gè)類(lèi)實(shí)例是否引用內(nèi)存中的同一位置(意味著它們具有相同的標(biāo)識(shí)),可使用靜態(tài) Equals 方法。(System.Object 是所有值類(lèi)型和引用類(lèi)型的隱式基類(lèi),其中包括用戶(hù)定義的結(jié)構(gòu)和類(lèi)。)
若要確定兩個(gè)結(jié)構(gòu)實(shí)例中的實(shí)例字段是否具有相同的值,可使用 ValueType.Equals 方法。由于所有結(jié)構(gòu)都隱式繼承自 System.ValueType,因此可以直接在對(duì)象上調(diào)用該方法,如下面的示例所示:
// Person is defined in the previous example. //public struct Person //{ // public string Name; // public int Age; // public Person(string name, int age) // { // Name = name; // Age = age; // } //} Person p1 = new Person("Wallace", 75); Person p2; p2.Name = "Wallace"; p2.Age = 75; if (p2.Equals(p1)) Console.WriteLine("p2 and p1 have the same values.");
輸出:
p2 and p1 have the same values.
Equals 的 System.ValueType 實(shí)現(xiàn)使用反射,因?yàn)樗仨毮軌虼_定任何結(jié)構(gòu)中有哪些字段。在創(chuàng)建您自己的結(jié)構(gòu)時(shí),重寫(xiě) Equals 方法可以提供針對(duì)您的類(lèi)型的高效求等算法。
上一篇:詳解C#中的接口屬性以及屬性訪(fǎng)問(wèn)器的訪(fǎng)問(wèn)限制
欄 目:C#教程
本文標(biāo)題:講解C#面相對(duì)象編程中的類(lèi)與對(duì)象的特性與概念
本文地址:http://mengdiqiu.com.cn/a1/C_jiaocheng/6733.html
您可能感興趣的文章
- 01-10C#實(shí)現(xiàn)獲取不同對(duì)象中名稱(chēng)相同屬性的方法
- 01-10C#日歷樣式的下拉式計(jì)算器實(shí)例講解
- 01-10C#導(dǎo)出網(wǎng)站功能實(shí)例代碼講解
- 01-10C#編程自學(xué)之類(lèi)和對(duì)象
- 01-10C#中Json字符串的各種應(yīng)用類(lèi)實(shí)例講解
- 01-10C#編程實(shí)現(xiàn)對(duì)象與JSON串互相轉(zhuǎn)換實(shí)例分析
- 01-10輕松學(xué)習(xí)C#的屬性
- 01-10使用C#實(shí)現(xiàn)讀取系統(tǒng)配置文件的代碼實(shí)例講解
- 01-10C#編程中使用ref和out關(guān)鍵字來(lái)傳遞數(shù)組對(duì)象的用法
- 01-10詳解C#面相對(duì)象編程中的繼承特性


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹(shù)的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問(wèn)題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 01-10C#通過(guò)反射獲取當(dāng)前工程中所有窗體并
- 01-10關(guān)于ASP網(wǎng)頁(yè)無(wú)法打開(kāi)的解決方案
- 01-10WinForm限制窗體不能移到屏幕外的方法
- 01-10WinForm繪制圓角的方法
- 01-10C#實(shí)現(xiàn)txt定位指定行完整實(shí)例
- 01-10WinForm實(shí)現(xiàn)仿視頻播放器左下角滾動(dòng)新
- 01-10C#停止線(xiàn)程的方法
- 01-10C#實(shí)現(xiàn)清空回收站的方法
- 01-10C#通過(guò)重寫(xiě)Panel改變邊框顏色與寬度的
- 01-10C#實(shí)現(xiàn)讀取注冊(cè)表監(jiān)控當(dāng)前操作系統(tǒng)已
隨機(jī)閱讀
- 01-10delphi制作wav文件的方法
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 04-02jquery與jsp,用jquery
- 01-10C#中split用法實(shí)例總結(jié)
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子
- 01-10SublimeText編譯C開(kāi)發(fā)環(huán)境設(shè)置
- 01-11Mac OSX 打開(kāi)原生自帶讀寫(xiě)NTFS功能(圖文
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?