C# 基礎知識系列- 4 面向對象

来源:https://www.cnblogs.com/c7jie/archive/2020/03/29/12593422.html

面向對象 面向對象是一個抽象的概念,其本質就是對事物以抽象的方式建立對應的模型。 簡單來講,比如我有一隻鋼筆,那麼我就可以通過分析,可以得到 這隻鋼筆的材第是塑料,品牌是個雜牌 ,裡面裝的墨是黑色的,可以用。這時候就能建立一個鋼筆的模型,它在這裡應該有這些屬性: 圖是一個不正確的UML類圖,但是可以 ...


面向對象

面向對象是一個抽象的概念,其本質就是對事物以抽象的方式建立對應的模型。
簡單來講,比如我有一隻鋼筆,那麼我就可以通過分析,可以得到 這隻鋼筆的材第是塑料,品牌是個雜牌 ,裡面裝的墨是黑色的,可以用。這時候就能建立一個鋼筆的模型,它在這裡應該有這些屬性:

file

圖是一個不正確的UML類圖,但是可以簡單的概述一下我們抽象的結果。這個圖就描述了一個我們抽象出來的鋼筆類應該有哪些特性,而我手裡的那隻鋼筆就可以看做是鋼筆類的一個實例。
簡單來講,面向對象編程就是針對一個事件或者說一個過程,找到這個過程中參與的所有人、事務或者相對獨立的個體,按照他們在這個過程中表現,提取出他們的特性,描述他們的行為,然後按照類別不同再抽象出類來。
所以,類是事物的概念抽象,事物是類的特殊實例。

創建一個類

上面簡單的介紹了面向對象的概念,現在先創建一個C#類,然後介紹一下這個類需要註意的地方:

public class Person
{
	private static int count;

	public static int Count
	{
		get { return count; }
		set { count = value; }
	}

	private string name;

	public string Name
	{
		get { return name; }
		set { name = value; }
	}
	public Person()
	{
		Name = "";
		Count = Count + 1;
	}

	public Person(string name)
	{
		this.Name = name;
	}

	public void SayHello()
	{
	}
}

其中:
private string name;private static int count;這兩個在C#中稱為Field,也就是欄位的意思;
public static int Countpublic string Name 這兩個在C#中稱為Property,也就是屬性的意思。
當然,不是說一個是private就叫欄位,另一個是public就稱之為屬性,而是因為屬性有getset來控制訪問和賦值的行為。

public Person()public Person(string name)是構造方法,所謂的構造方法就是初始化一個實例的方法,調用形式如下:
Person p = new Person() 通過new關鍵字+類名+對應的參數列表即可。構造方法沒有返回類型,方法名必須是類名,可以有任意個參數。

面向對象的三大特性

面向對象的三大特性是封裝、繼承、多態。我把它們稱為面向對象面試三巨頭,因為一旦面試,如果有面向對象的問題絕對會問到這三個特性。這裡先簡單介紹一下三大特性,

  • 封裝:對象的方法實現對外是隱藏的,就像我們在不拆開鋼筆之前很難知道鋼筆的墨水是怎麼流動然後寫出字的;
  • 繼承:子類天然擁有父類的屬性和方法,假如我們還有一隻特種鋼筆,那麼我們可以把這隻特種鋼筆抽象出的類認為是鋼筆的子類,這隻特種鋼筆跟鋼筆一樣,可以用來做鋼筆能做的事,雖然有時候不好用;
  • 多態:簡單來講就是多種狀態,對於面向對象來說,就是方法重寫和方法重載。比如說,我們去找領導簽字,領導在忙讓我們把文件放那邊,過一會領導派人送過來簽好字的文件。如果領導有多只鋼筆,那麼領導用哪只筆、在什麼時候、用什麼姿勢對於我們來說就是不確定的狀態,這就是多態的一種。

訪問控制符

在將三大特性之前,先介紹一下 C#的訪問控制。C#常用的訪問控制分為四種:

  • private: 限定只有同屬於一個類的成員才可以訪問,如果限定一個類是私有類,那麼這個類必須是內部類
  • protected: 限定當前類的成員、子類可以訪問,不能用來限定外部類,同private一樣,如果限定類是受保護類,這個類必須是內部類
  • internal(default):預設訪問許可權,對於類和方法來說,限定同一個DLL可以訪問,其他DLL不能訪問。區別是類的 internal 關鍵字可以省略,方法如果省略訪問許可權符,則預設是protected
  • public:公開,所有能引用類的地方都能訪問類里的public對象,這是最開放的許可權。

C#還有更多的訪問控制,不過常用的只有這四種,更多的可以參照【官方文檔】。

封裝

封裝簡單來講就是調用方不知道被調用方的具體實現以及內部機制,就像我們看別人只能看到外表缺看不到器官的運作(當然除非你是醫生)。
那麼封裝有什麼好處呢:

  • 對外隱藏實現,防止外部篡改引發安全問題
  • 減少不必要的關聯,被調用方需要調用方提供參數,但除此之外調用方只需要靜待被調用方返回結果就行
  • 打包一系列的操作,防止中間發生變故

比如說一個鐘錶,給我們一堆零件,在沒有拼接、安裝好之前也就是封裝好,這個鐘錶是不能正常使用的。只有我們按照一定邏輯,將零件安裝好之後(封裝),再裝上電池或上發條(調用) 鐘錶才會轉起來。
簡單的用代碼介紹一下:

class Program
{
	static void Main(string[] args)
	{
		Person p = new Person();
		p.SayHello();
	}
}


public class Person
{
	private static int count;

	public static int Count
	{
		get { return count; }
		set { count = value; }
	}

	private string name;

	public string Name
	{
		get { return name; }
		set { name = value; }
	}

	public Person()
	{
		Name = "小明";
		Count = Count + 1;
	}

	public Person(string name)
	{
	}

	public void SayHello()
	{
		Console.WriteLine("你好,我叫"+Name);
	}
}

簡單看一下,對於Program類來講,Person的SayHello是怎麼實現的完全不知情。這就是封裝的意義。

繼承

C#的繼承是單繼承,也就是說一個類只有一個父類,如果不指明父類,那麼它的父類就是object。換句話說,object是C#繼承體系裡的根,也就是所有類的祖先類。
C#的繼承用 表示,即 class B: A表示B繼承A。

public class A
{
	public virtual void Say()
	{
	}
	public void Look()
	{
	}
}
public class B : A
{
	public override void Say()
	{
	}
}

上述代碼建立了一個簡單的繼承體系。那麼問題來了,繼承有什麼用呢?簡單來講,對於A和B在Say方法有不同的實現,對於調用方來講,它們的表現應當是一致的。換句話說,就是所有用到A的地方,都能用B來代替,這不會出現任何問題。
繼承可以簡化很多行為(方法)一致的寫法。如示例所述,B類在Look上與其父類A類有著一致的行為和表現,那麼B就可以省略了Look的定義和描述,沿用父類的方法。通過繼承可以很快地建立一套豐富的方法體系。子類每一次對父類的方法補充都會在子類里體現出來。所以繼承可以說是面向對象的核心體系。

有個關鍵字需要額外的講解一下saled,如果看到一個類有這個標記,那麼需要註意了,這個類是不可被繼承的類。

多態

多態的實現就是通過類的繼承和方法的重載實現的。類的繼承主要通過重寫父類方法或者覆蓋父類方法來實現的,主要關鍵字就是 virtualoverridenew
具體的介紹是:

  • virtual 關鍵字聲明函數為虛函數,意思就是子類可能會重寫該方法
  • override 用在子類,用來聲明該方法是重寫父類的方法
  • new 跟實例化對象的new不同,這個放在方法前的意思是該方法會隱藏父類方法的實現。
public class A
{
	public virtual void Say()
	{
		//省略實現
	}

	public void SetName()
	{
		//省略實現
	}
}

public sealed class B:A
{
	public override void Say() //重寫父類方法
	{
		//省略實現
	}
	public new void SetName() // 覆蓋父類方法
	{
		//省略實現
	}
}

重寫和覆蓋的區別在哪呢:

A a = new B();
a.Say();// 調用的是 B中 Say方法
a.SetName();//調用的是A的SetName 方法
B b = (B)a;
b.SetName();//調用的是B的SetName 方法
b.Say();// 調用的是 B中 Say方法

類和介面

C#中類和介面的聲明方式不同,類用的關鍵字是class,介面用的是interface。而且類是繼承,介面是實現,一個類只能有一個父類,介面可以有多個。
介面需要註意的地方就死,介面所有的方法都是public的,因為介面就是用來定義規範的,所以一旦它的方法訪問控制不是public的話,就沒什麼意義。

public class Demo1
{
}
public interface IDemo
{
	string Method();
}
public class Demo3 : Demo1, IDemo
{
	public string Method()
	{
		return "test";
	}
	string IDemo.Method()
	{
		return "test2";
	}
}

介面的實現和類的繼承都是 : ,先繼承後實現。

觀察示例代碼,發現Demo3有兩個方法public string Method()string IDemo.Method() 。這兩個都是實現介面的方法,不同的地方是它們的使用:

IDemo idemo = new Demo3();
idemo.Method();//返回 test2
Demo3 demo = new Demo3();
demo.Method();// 返回 test

使用介面名.方法名實現方法的時候,這個方法對於實現類構造的對象來說是不可訪問的。當然兩種方法可以共存,但是不會兩個方法都被認為是介面的實現方法。介面優先使用介面名.方法名 作為實現方法,如果沒找到則認為同名同參的方法為實現方法。

Object 類 常用方法

object 作為基類定義了四個基本方法,這四個方法是所有子類都有的方法,也是一個核心方法:

  • Equals(object obj) 這是一個很重要的方法,它是 C#中判斷兩個對象是否相等的依據,也就是 == 運算符的結果,如果不重寫這個方法的話,返回的結果是兩個對象是否指向同一個引用地址。
  • GetType() 返回這個對象的類型,這是反射機制中重要的一塊
  • ToString() 返回字元串,獲得一個對象的文字描述,預設返回的是對象的地址描述信息,這個方法建議重寫
  • GetHashCode() 返回 Hash值,某些集合和程式機制會以HashCode作為元素的相等性判斷依據,所以在重寫 Equals 之後也要重寫 這個方法,並保證兩個方法對於相同的對象做相等性結果判定是應該表現一致。

擴展方法

C# 有一個很重要的機制就是擴展方法,擴展方法表現出的跟類自有的方法調用結果一致。
具體寫法如下:

public static class Methods
{
	public static string Test(this Person person)
	{
			return "test";
	}
}

需要註意的是,擴展方法所在類必須是靜態類,擴展方法必須是靜態方法,擴展方法第一個參數就是擴展的元素對象,用this標記。

不過很多人對擴展方法褒貶不一,有人認為擴展方法極易破壞繼承鏈,導致一些不必要的麻煩;有人認為擴展方法就跟工具方法一樣,而且可以優化調用方式,統一使用風格。

不過我看來,擴展方法利大於弊。因為擴展方法可以在不修改原有類的基礎上增加功能,同時它也是一個工具類,跟普通的方法是一致的。

更多內容煩請關註我的博客

file


您的分享是我們最大的動力!

更多相關文章
  • Druid簡介 Druid是阿裡開源的資料庫連接池,作為後起之秀,性能比dbcp、c3p0更高,使用也越來越廣泛。 druid的優點 高性能。性能比dbcp、c3p0高很多。 只要是jdbc支持的資料庫,druid都支持,對資料庫的支持性好。並且Druid針對oracle、mysql做了特別優化。 ...
  • public static <T> T map2Object(Map<String, Object> map, Class<T> clazz) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); if (map ...
  • A - Coffee 題意:給你一個字元串,要你判斷是否滿足一下條件,全部滿足則輸出“Yes”,否則輸出“No”。 (1)字元串的第3個字母等於字元串的第4個字母 (2)字元串的第5個字母等於字元串的第6個字母 (3)字元串的長度為6,且全部為小寫字母 題解:簽到題,易解 代碼: #include< ...
  • 一、背景 一方面,有時必須從幾個類中派生出一個子類,繼承它們所有的屬性和方法。但是,Java不支持多重繼承。有了介面,就可以得到多重繼承的效果。 另一方面,有時必須從幾個類中抽取出一些共同的行為特征,而它們之間又沒有is-a的關係,僅僅是具有相同的行為特征而已。 二、圖示 三、介面的使用 1.介面: ...
  • 隨著繼承層次中一個個新子類的定義,類變得越來越具體,而父類則更一般,更通用。類的設計應該保證父類和子類能夠共用特征。有時將一個父類設計得非常抽象,以至於它沒有具體的實例,這樣的類叫做抽象類。 舉例: public class test { public static void main(String ...
  • 發現按照教程操作破解Eplan,破解一直不成功。主要原因是MultiKey64在win10上運行不成功。可以通過設備管理看到是否有下圖的驅動 需要關閉win10的簽名認證,這個鏈接就是關閉的方法https://jingyan.baidu.com/article/624e74594dbc8d34e8b ...
  • 你需要瞭解的 HTTP Status Code Intro 現在前後端分離的開發模式越來越流行,後端負責開發對應的 API,前端只需要 關註前端頁面的數據展示和前端邏輯即可。 對於前後端分離這種開發模式,我個人還是比較喜歡的,因為這樣可以讓更專業的人做更專業的事情,後端專註於做 API 的開發設計, ...
  • 在ASP.NET MVC中有四種過濾器類型 Action 1、在ASP.NET MVC項目中,新建文件夾Filter,然後新建類MyCustormFilter,繼承自ActionFilterAttribute類,我們來看下ActionFilterAttribute類有如下四個方法,從命名我應該就可以 ...
一周排行
  • 一:背景 1. 講故事 如果你常翻看FCL的源碼,你會發現這裡面有不少方法藉助了C/C++的力量讓C#更快更強悍,如下所示: [DllImport("QCall", CharSet = CharSet.Unicode)] [SecurityCritical] [SuppressUnmanagedCo ...
  • 上一篇(https://www.cnblogs.com/meowv/p/12966092.html)文章使用AutoMapper來處理對象與對象之間的映射關係,本篇主要圍繞定時任務和數據抓取相關的知識點並結合實際應用,在定時任務中迴圈處理爬蟲任務抓取數據。 開始之前可以刪掉之前測試用的幾個Hello ...
  • 首先創建實體類 1 public class MacState 2 { 3 /// <summary> 4 /// 請求狀態 5 /// </summary> 6 public string success { get; set; } 7 /// <summary> 8 /// 錯誤信息 9 /// ...
  • 0. 前言 前幾天FreeSql的作者向我推薦了FreeSql框架,想讓我幫忙寫個文章介紹一下。嗯,想不到我也能帶個貨了。哈哈,開個玩笑~看了下覺得設計的挺有意思的,所以就謝了這篇文章。 簡單介紹一下,FreeSql 是NCC組織的沙盒級項目,是一款功能強大的 ORM 組件,支持 .NET Core ...
  • 0. 前言 這是一個新的系列,名字是《ASP.NET Core 入門到實戰》。這個系列主講ASP.NET Core MVC,輔助一些前端的基礎知識(能用來實現我們需要的即可,並非主講)。同時這個系列也會在後續介紹ASP.NET Core 平臺的其它類型的項目,並帶領大家以各個類型的項目為主要架構開發 ...
  • 我寫了一個Winform測試程式,用的System.Timers.Timer,在事件里,設置label1.Text,然後,居然句柄泄漏、用戶對象泄漏! 百思不得其解,最後換成System.Windows.Forms.Timer,居然不泄漏了! 最近睡眠不足,哪怕一個很小的問題,隨便搞搞,都半夜了! ...
  • leetcode-7. 整數反轉。 給出一個 32 位的有符號整數,你需要將這個整數中每位上的數字進行反轉。 示例 1: 輸入: 123 輸出: 321 示例 2: 輸入: -123 輸出: -321 示例 3: 輸入: 120 輸出: 21 註意: 假設環境只能存儲得下 32 位的有符號整數,則其 ...
  • 1. Java 虛擬機是什麼? 1.1 虛擬機 虛擬機:虛擬的電腦,一個用來執行虛擬電腦指令的軟體。 虛擬機分為系統虛擬機和程式虛擬機。 系統虛擬機:提供一個可運行完整操作系統的軟體平臺,如 Visual Box、VMware。 程式虛擬機:專門執行單個程式的,典型代表 Java 虛擬機。Jav ...
  • 前言 - strlen 概述 無意間掃到 glibc strlen.c 中代碼, 久久不能忘懷. 在一無所知的編程生涯中又記起點點滴滴: 編程可不是兒戲 ❀, 有些難, 也有些不捨. 隨軌跡一同重溫, 曾經最熟悉的 strlen 手感吧 ~ /* Copyright (C) 1991-2020 Fr ...
  • 背景 隊列[Queue]:是一種限定僅在表頭進行刪除操作,僅在表尾進行插入操作的線性表;即先進先出(FIFO-first in first out):最先插入的元素最先出來。 本文通過編碼實現鏈式隊列類,並模擬一個有趣的應用,能夠幫助我們對鏈式隊列有更深度的理解。 基本概念 結點 每個元素,除了存儲 ...