本節內容ios
1.方法的由來;算法
2.方法的定義與調用;ide
3.構造器(一種特殊的方法);函數
4.方法的重載(Override);佈局
5.如何對方法進行debug;spa
6.方法的調用與棧*debug
*推薦書目:CLR via C#和C# in Depth, 3rd Editionorm
1.方法的由來對象
①方法(method)的前身是C/C++語言的函數(function)遞歸
方法是面向對象範疇的概念,在非面嚮對象語言中仍然稱爲函數。
可使用C/C++語言作對比。
*當函數以成員的身份出現時咱們就叫它方法(始於C++)
②永遠都是類(或結構體)的成員
C#語言中函數不可能獨立於類(或結構體以外)。
只有做爲類(或結構體)的成員時才被稱爲方法。
而在C++中是能夠的,稱爲「全局函數」。
③是類(結構體)最基本的成員之一
最基本的成員只有兩個——字段與方法(成員變量與成員方法),本質仍是數據+算法
方法表示類(或結構體)「能作什麼事情」。
④爲何須要方法和函數
目的1:隱藏複雜的結構;
目的2:複用(resue,重用);
C++中#include<iostream>
#include "Student.h"//若是是標準類庫的話用尖括號,若是是本身定義的則用引號。
2.方法的聲明與調用
①聲明方法的語法詳解
參見C#語言文檔(聲明/定義不分家);
Parameter全稱爲」formal parameter」;
形式上的參數,簡稱」形參」:形式參數參與構成算法的算法邏輯(即在算法中做爲變量參與計算);
Parameter是一種變量:形式參數變量;
②方法的命名規範:
大小寫規範:pascal法則(每一個單詞首字母大寫);
須要以動詞或者動詞短語做爲名字;
③重溫靜態(static)方法和實例方法:靜態方法是隸屬於類的,類的對象不能調用;實例方法(非靜態方法)隸屬於類的對象,對象能夠調用。
④調用方法:方法名後面的圓括號不能省略。
聲明函數時」()」裏面的是形參;調用函數時」()」裏面是實參。
Argument中文C#文檔的官方譯法爲」實際參數」簡稱」實參」可理解爲調用方法時的真實條件。
調用方法時的Argument列表要與定義方法時的parameter列表相匹配,C#是強類型語言,argument是值,parameter是變量,值與變量(個數與數據類型)必定要匹配否則會報錯。
3.構造器
構造器(constructor)是類型的成員之一;
狹義的構造器是指「實例構造器」(instance constractor);
如何調用構造器;
聲明構造器;
構造器的內存原理;
構造函數的做用爲構造類的實例(對象)並初始化。
①當調用默認構造函數時:
如語句:Student stu=new Student();①
Class Student
{
Public int ID;
Public string Name;
}
*因爲①語句是在main函數了的,stu引用變量爲局部變量,先在棧中分配4個字節的空閒內存;*new操做符建立了Student類的一個實例,經過調用Student();默認構造函數,在堆內存中開闢一塊空內存大小爲該實例所包含的數據之和的空間存放實例,(int ID;4個字節,string name4個字節)因此分配8個字節的內存空間,因爲默認構造函數默認賦值爲0,故該塊內存裏的數據初始值爲0;*最後將該內存的首地址轉化爲2進制數,複製到引用變量stu的棧內存當中。
②當調用有參構造函數時:
第一步和第三步操做與調用默認構造函數時相同;不一樣之處在於第二步:
&當參數爲數值類型時:首先在堆內存上這8字節的實例內存空間裏,int類型佔4個字節,傳進來的實參值爲1(假設)則把1(都要轉化爲2進制)轉化爲2進制存在該內存裏;
&當參數爲引用類型時(記住凡是類類型都是引用類型):剩下的4個字節是string類型的存儲空間,(假設傳進來的實參爲」it’OK」)
因爲string是類類型的,而類類型是引用類型,因此,這4個字節裏面存放的只是引用變量,還要再去堆內存中找一塊位置存放實參」it’OK」。找到內存空間後把」it’sOK」這個字符串數據轉化爲2進制數據存入其中。(最後該內存首地址轉化爲2進制存在string類型棧內存中與上面一致)
4.方法的重載(Overload)
①調用重載方法的示例;
②聲明帶有重載的方法
方法簽名(method signature)由方法的名稱、類型形參(講泛型的時候會遇到)的個數和它的每個形參(按從左到右的順序)的類型和種類(值、引用(ref)或輸出(out))組成。方法簽名不包含返回值。(主要看方法名和參數列表)
實例構造函數簽名由它的每個形參(按從左到右的順序)的類型和種類(值、引用或輸出)組成;
重載決策(到底調用哪個重載):用於在給定了參數列表和一組候選函數成員的狀況下、選擇一個最佳函數成員來實施調用。
5.如何對方法進行debug(核心技能)
設置斷點(breakpoint);
觀察方法調用時的call stack;
Step-in,Step-over,Step-out;
觀察局部變量的值與變化。(能夠經過局部變量窗口觀察,還能夠把鼠標放在變量上觀察,也能夠把鼠標放在變量上出現的小窗口固定住來觀察)
調用棧(call stack)和內存棧的關係:好比遞歸,不斷的調用本身,直到有一箇中止的值,若沒有,則調用棧就會愈來愈深直到把內存棧佔爆了,這時候就stackOverflow(棧溢出)
Step-in(F11)(逐語句):進入方法當中,最細膩的debug手段
Step-over(F10)(逐過程):不走進方法直接跳過去,比較粗獷一些的debug手段
通常爲二者結合使用,先用F10快速的大範圍的排查是哪一個方法出現問題再使用F11走進方法一步一步debug。(懷疑有bug的地方就F11仔細的排查)
Step-out(跳出):做用爲跳轉到調用斷點當前方法的類或方法裏面(按順序)例如3調用2,2調用1,則在1中設置斷點,第一次按Shift F11跳到2處,再按一次跳轉到3處。
*綜合使用這三種方法會使咱們具備強大的debug能力。
6.方法的調用與棧
①方法調用時棧內存的分配
對stack frame(一個方法在被調用過程當中棧內的佈局)的分析
*棧內存由高字節位向低字節位發展,發展到最低限度以後就會Overflow,
例如C#fun中的main函數輸出語句依次調用三個方法,調用時,main方法先在棧內存裏開闢一個內存空間叫stack frame(棧幀)。
方法的調用關係有調用和被調用,調用者叫作Caller,被調用者叫作Callee,那麼問題來了好比main函數中調用其餘函數: Console.WriteLine(c.GetConeVolume(100, 100));那麼傳進去的兩個參數(100)哪一個函數來管理呢,不一樣的語言規定不一樣,C#是按C++的標準,參數歸主調者(caller)管,就是這裏的main管。在棧內存中分別開闢參數相應類型大小的空間,先壓哪一個參數進去呢?不一樣的語言規定不一樣,C#聽從C++的規則先左後右,誰調用誰負責把參數壓進棧裏故該片內存也是由main管(也是main函數的stack frame),*即方法運行時都先在棧內開闢stack frame內存空間 再把方法內包含的數據都壓進該片棧內存中。如今開始方法的調用,遵循誰調用誰壓棧的原則,即便方法內無局部變量該方法也會有stack frame(存放方法返回值地址等),方法的返回值是存在cpu的寄存器(學彙編時有講到)裏面的。
*一個方法運行完的出結果返回了值以後,相應的stack frame(棧幀)就會被清空,相應的函數(方法)調用結束相關參數沒有用了其在棧幀中的內存也會被清空。(能夠聯想彙編語言的壓棧與出棧)
*這裏也能夠解釋一下overflow,就是由於異常方法一直調用,一直
開闢棧幀,沒有一層層的返回,相應參數只進棧不出棧,直至開闢空間到棧頂形成「棧溢出」這就是棧溢出的原理。