c#構造方法
(教學思路 C#之類四)構造方法(靜態構造方法、this、方法重載)、析構方法(修改新增)
--------------------------------------------------------------------------------
2008-12-13 22:43:00 標籤:教學思路 C# 構造方法 方法重載 析構方法 [推送到技術圈]
版權聲明:原創作品,如需轉載,請與作者聯繫。否則將追究法律責任。
今天這節課我們來學習類的構造方法和析構方法,同學們現在回憶一下在類一系列中,學習到創建一個類ClassName的實例,也就是對象ObjName時基本語法爲:ClassName ObjName=new ClassName();我說過,new後面的ClasName()實際上指的是這個類的構造方法,而且我也說過,這個()中可以有參數,這個有參數,就是指構造方法可以有參數,那麼什麼是類的構造方法呢?
構造方法
--------------------------------------------------------------------------------
構造方法又叫構造函數,也有人叫做構造器,其實就是對類進行初始化。構造方法是一種特殊的方法,在類實例創建之前執行,用來初始化對象,完成對象創建前所需的相關設定,構造方法允許將類實例初始爲有效狀態的特殊方法,這就是構造方法的定義,用通俗的話說,就是開車前的暖車工作,用洗衣機之前的接上電源的工作,參數可以有多個可以這樣理解,洗衣機的插頭有兩頭的、有三項的,在創建洗衣機對象的時候,要分清插頭的種類,才能創建成功對象。
爲什麼說構造方法是特殊的方法呢?因爲構造方法本身沒有返回值,並且通常是public訪問類型,方法的名稱必須與類名相同,當我們沒有明確的在類中定義構造方法的時候,例如我們以前所定義的類,都是沒有定義構造方法的,這時系統會使用默認的構造方法,如創建ClassName類的默認構造方法,public ClassName(){}。默認的構造方法並沒有進行任何類初始化行爲,你可以自己定義構造方法,當然如果你有自定義構造方法,那麼默認的構造方法就會失效了。也就是說,當我們在ClassName類中沒有定義構造方法時,C#語言會生成一個空的構造方法ClassName(),當然這個空的方法是什麼也沒做,只是爲了讓我們定義的類能夠在創建對象時順利的實例化而已。
構造方法可以有兩個,因爲參數的不同區別開,這就構成了方法的重載,方法重載的最大的好處在與可以利用相同的名稱來組織應用程序的方法成員,當一個複雜的類被創建的時候,對功能相同的方法最好採用相同的命名方式,用不同的參數來區別,比如,計算面積時,我們就可以把四邊形面積的計算方法的名字起同一個,用參數來區別如正方形定義一個參數(一個邊長),長方形定義三個參數(一個長,一個寬,另一個長方形的標誌如0),梯形定義三個參數(一個底,一個高,另一個梯形的標誌如1),通過第三個參數標誌區別長方形和梯形不同的面積公式。方法的重載要注意的是,方法名相同,但是參數類型或個數必須要有所不同,方法重載的優點就是可以在不改變原方法的基礎上,新增功能。
下面我們來看實例,通過實例我們來體會構造方法是如何在創建對象時初始化的。
構造方法實例
namespace hello
{
//創建一個人類Ren
class Ren
{
/*觀察字段成員如果不賦初值時,在創建對象的時候,
* 編譯器會按照類型默認的給變量一個初值,如年齡、姓名
* 我們可以在構造方法中,對未賦值的字段進行改變,如年齡
* 如果字段已經賦初值了,那麼創建對象的時候,
* 就會使用初值,如果需要改變,就在構造方法中重新賦值即可,如性別*/
//定義一個年齡變量,不賦初值
int age;
//定義一個姓名變量,不賦初值
string name;
//定義一個性別變量,賦初值爲男
string Sex = "男";
//定義一個方法,讀取類中字段成員,值的變化。
void Say()
{
Console.WriteLine("我的年齡:{0},我的名字:{1},我的性別:{2}", age, name,Sex );
}
/*1.以下方法都爲Ren這個類的構造方法,他們因爲參數不同,形成了方法的重載,
* 2.this關鍵字:this關鍵字用來引用對象本身,已經是說,this.name指的是對象中的name字段,
* 而=name的這個name指的是方法中離它定義最近的name,這裏值的是構造方法中傳入的name參數
* this關鍵字在例子結束後,還會具體的講解。*/
//在無參的構造方法中,給性別重新賦值,年齡和姓名按照創建對象時默認的賦初值
public Ren()
{
//改變性別的值
Sex = "女";
Console.WriteLine("我剛出生!還沒有名字,年齡也從0歲開始!");
//此時讀取對象中的字段值的變化,應該性別改變,年齡和姓名都爲默認值
Say();
}
//創建一個帶姓名參數的構造方法,將創建對象時傳入的name參數賦給對象中的字段name值,這樣say方法中的姓名也有了改變
//同時在這個構造方法中,給age字段自定義賦值。
public Ren( string name )
{
this. name =name ;
Console.WriteLine("呦!我使用雙截棍,我有名字了!,但是年齡呢?,我自己定,我就27歲了。");
age = 27;
Say();
}
//創建一個帶姓名參數、姓名的構造方法,將創建對象時傳入的name參數賦給對象中的字段name值,
//將創建對象時傳入的age參數的值賦給對象中的字段age,這樣say方法中的姓名、年鄰都有了改變
public Ren(int age, string name)
{
this.age = age;
this.name = name;
Console.WriteLine("哦!你給我起名字,告訴我多大了吧!你說的算!");
Say();
}
//定義靜態的構造函數,我把她放在在最後,但是會第一個被調用。
static Ren()
{
Console.WriteLine("我是靜態的構造函數,不能有參數及訪問修飾符,並且創建對象時,我只執行一次,最先調用");
Console.WriteLine();
}
}
class Program
{
static void Main(string[] args)
{
//創建無參的對象boby,並且創建時會先調用靜態的構造方法,再調用無參的構造方法
Ren boby = new Ren();
Console.WriteLine();
//創建有姓名參數的對象songer歌手
Ren songer = new Ren("周杰倫");
Console.WriteLine();
//創建有年齡、姓名參數的對象man
Ren man = new Ren(33,"貝克漢姆");
Console.WriteLine();
}
}
}
結果如下
我是靜態的構造函數,不能有參數及訪問修飾符,並且創建對象時,我只執行一次,最先調用
我剛出生!還沒有名字,年齡也從0歲開始!
我的年齡:0,我的名字:,我的性別:女
呦!我使用雙截棍,我有名字了!,但是年齡呢?,我自己定,我就27歲了。
我的年齡:27,我的名字:周杰倫,我的性別:男
哦!你給我起名字,告訴我多大了吧!你說的算!
我的年齡:33,我的名字:貝克漢姆,我的性別:男
在上面的例子中同學們會觀察到我定義了一個static Ren(){}的構造方法被稱爲靜態構造方法。構造方法的重載中還包括一種,在方法的名字前的修飾符只有static,稱爲靜態構造方法,使用靜態構造方法要注意以下幾點:
1.靜態構造方法只有一個;
2.並且沒有參數;
3在所有的構造方法中最先被執行;
4.靜態的構造方法不會被繼承,因爲它的修飾符是私有的並且只能是私有的;
5.靜態構造方法在所有靜態成員本初始化後執行,也就是說如果在類中定義了靜態成員,就會自動生成一個靜態構造方法,否則如果要使用靜態構造方法就得自定義。
6.靜態構造方法在所有靜態成員被引用之前執行。
7.靜態構造方法在所有實例成員被分配之前執行。
本例中還出現了this關鍵字,下面我們來說說this關鍵字,this關鍵字最大的用途就是用來區分類級別的變量和局部變量,當一個位於方法內部的局部變量與類級別的變量名稱相同的時候,因爲有效區域不同,因爲並不不會發生衝突,但是如此一來,在方法內部所訪問的變量,一定是其中所定義的局部變量,而非類級別的同名變量,在這種情況下,我們就使用this關鍵字,比如第一個實例中,用this代表對象本身,this.name指的是類級別中定義的name字段.使用this雖然可以讓我們分辨出不同級別的變量,但是最好還是起不同的名字來區分變量。this關鍵字還有一種用法,就是在同類的構造方法中,指代無參的構造函數,使用:this()來實現繼承。下面我們來看靜態構造方法和this關鍵字的構造方法繼承用法實例:
靜態構造方法和this關鍵字
1 class StaticTest
2 {
3 //如果i沒有初值,編譯器不會自動創建靜態構造方法。
4 public static int i = 1;
5
6 //創建自定義的靜態構造器,觀察它的執行順序。
7 static StaticTest()
8 {
9 Console.WriteLine("我應該在1的前面被調用,我只被調用一次。");
10 }
11
12 //定義私有的實例變量j和s,不賦初值
13 int j;
14 string s;
15
16 //定義無參的構造器,同時給j和s賦值
17 public StaticTest()
18 {
19 Console.WriteLine("我是無參構造器!,我給j賦值後,只要繼承我,使用:this(),你們的j和s都是這個值");
20 j = 10;
21 s = "原來的值";
22 }
23
24 //通過:this()方式,繼承了j和s的值
25
26 public StaticTest(string ss):this()
27 {
28 //此時j=10,如果沒有繼承,j=0.
29 Console.WriteLine("j=" + j);
30
31 //通過傳參進入的值,改變了繼承了無參構造器中s的值,
32 //說明即使繼承了s的值,也可以在本構造方法中改變s的值
33 s = ss;
34 Console.WriteLine(s);
35
36 }
37 }
38 class Program
39 {
40 static void Main(string[] args)
41 {
42 //先調用靜態成員i的值,結果會是先執行靜態構造方法,再顯示i=1;
43 Console.WriteLine("用我前,先會查看是否有靜態構造方法的定義,如果有先執行它,再得出i="+StaticTest.i);
44 Console.WriteLine("-------------");
45
46 //此時不會再出現static構造器的內容,因爲前面已經執行了一次。
47 StaticTest A = new StaticTest();
48 Console.WriteLine("-------------");
49
50 //觀察j和s值的變化:
51 StaticTest B = new StaticTest("s的值改變了");
52
53 }
54 }
結果如下我應該在1的前面被調用,我只被調用一次。
用我前,先會查看是否有靜態構造方法的定義,如果有先執行它,再得出i=1
-------------
我是無參構造器!,我給j賦值後,只要繼承我,使用:this(),你們的j和s都是這個值
-------------
我是無參構造器!,我給j賦值後,只要繼承我,使用:this(),你們的j和s都是這個值
j=10
s的值改變了
通過上面的實例和註釋,對照運行結果,同學們要熟練的運用和理解。
因爲我們現在還沒有學習到繼承,其實在一個類創建成對象的時候,創建時,編譯器會先看這個類是否有父類,如果有父類,再繼續找是否有父類的父類,我習慣叫爺爺類,如果有爺爺類,再看有沒有太爺爺類,如果沒有太爺爺類,就會先執行爺爺類的構造方法,再執行爸爸類的構造方法,最後才執行自己的構造方法,當然所有的構造方法的繼承都是指實例構造函數,靜態的構造函數是無法被繼承的。下面的實例就是一個構造方法的繼承順序,現在看不懂沒有關係,只是想讓大家瞭解創建對象的工作過程,這裏提前講一個知識點就是繼承的語法如A是父類,B是子類,那麼在定義B類的時候,語法是這樣寫的Class B:A,用“:”來表明繼承關係,在java中是用“extends”關鍵字,現在看看代碼,理解一下構造方法的繼承結果:
構造方法在繼承中的順序
class Class1 可以看出,類在繼承時,構造函數在實例化的過程中,是會被再次調用的。
{
static void Main()
{
Console.WriteLine("**********");
A a = new A();
Console.WriteLine("**********");
B b = new B();
Console.WriteLine("***** AC : A*****");
AC ac = new AC();
Console.WriteLine("*****BC : B*****");
BC bc = new BC();
Console.WriteLine("*****CC : AC*****");
CC cc = new CC();
Console.WriteLine("*****CCC : BC*****");
CCC ccc = new CCC();
}
}
class A
{
public A()
{
Console.WriteLine("Call method A()");
}
}
class B
{
public B()
{
Console.WriteLine("Call method B()");
}
}
class AC : A
{
public AC()
{
Console.WriteLine("Call method AC()");
}
}
class BC : B
{
public BC()
{
Console.WriteLine("Call method BC()");
}
}
class CC : AC
{
public CC()
{
Console.WriteLine("Call method CC()");
}
}
class CCC : BC
{
public CCC()
{
Console.WriteLine("Call method CCC()");
}
結果如下:**********
Call method A()
**********
Call method B()
***** AC : A*****
Call method A()
Call method AC()
*****BC : B*****
Call method B()
Call method BC()
*****CC : AC*****
Call method A()
Call method AC()
Call method CC()
*****CCC : BC*****
Call method B()
Call method BC()
Call method CCC()
請按任意鍵繼續. . .
雖然我沒有寫註釋,但是相信同學們都應該能理解這個過程,構造器的繼承我也會在類七中再繼續深化講解。構造方法的出現使得我們開發人員可設置默認值、限制實例化以及編寫更加靈活且便於閱讀的代碼。接下來我們來學習本節課最後一個知識點,析構方法。
析構方法
--------------------------------------------------------------------------------
析構方法也叫銷燬方法,也有人稱爲析構器,類藉助構造方法進行對象的初始化,藉助析構方法進行對象的終止操作,析構方法也是使用類名相同的名稱命名,用“~”修飾,當對象被系統終止並且回收時,析構方法執行,我們可以在析構方法中寫方法,它會最後被執行,析構方法的語法書寫如:~ClassName(){},析構函數是不能有參的,並且一個類中只能有一個析構方法,類中有幾個構造方法,析構方法就有被執行幾次。我們把上面的實例中加入析構方法,再執行一次代碼。
加入析構方法的第一個實例
namespace hello
{
//創建一個人類Ren
class Ren
{
//雖然我把析構方法寫在最上面的,但是它是最後執行的方法。
~Ren()
{
Console.WriteLine("滅亡了");
}
/*觀察字段成員如果不賦初值時,在創建對象的時候,
* 編譯器會按照類型默認的給變量一個初值,如年齡、姓名
* 我們可以在構造方法中,對未賦值的字段進行改變,如年齡
* 如果字段已經賦初值了,那麼創建對象的時候,
* 就會使用初值,如果需要改變,就在構造方法中重新賦值即可,如性別*/
//定義一個年齡變量,不賦初值
int age;
//定義一個姓名變量,不賦初值
string name;
//定義一個性別變量,賦初值爲男
string Sex = "男";
//定義一個方法,讀取類中字段成員,值的變化。
void Say()
{
Console.WriteLine("我的年齡:{0},我的名字:{1},我的性別:{2}", age, name,Sex );
}
/*1.以下方法都爲Ren這個類的構造方法,他們因爲參數不同,形成了方法的重載,
* 2.this關鍵字:this關鍵字用來引用對象本身,已經是說,this.name指的是對象中的name字段,
* 而=name的這個name指的是方法中離它定義最近的name,這裏值的是構造方法中傳入的name參數
* this關鍵字在例子結束後,還會具體的講解。*/
//在無參的構造方法中,給性別重新賦值,年齡和姓名按照創建對象時默認的賦初值
public Ren()
{
//改變性別的值
Sex = "女";
Console.WriteLine("我剛出生!還沒有名字,年齡也從0歲開始!");
//此時讀取對象中的字段值的變化,應該性別改變,年齡和姓名都爲默認值
Say();
}
//創建一個帶姓名參數的構造方法,將創建對象時傳入的name參數賦給對象中的字段name值,這樣say方法中的姓名也有了改變
//同時在這個構造方法中,給age字段自定義賦值。
public Ren( string name )
{
this. name =name ;
Console.WriteLine("呦!我使用雙截棍,我有名字了!,但是年齡呢?,我自己定,我就27歲了。");
age = 27;
Say();
}
//創建一個帶姓名參數、姓名的構造方法,將創建對象時傳入的name參數賦給對象中的字段name值,
//將創建對象時傳入的age參數的值賦給對象中的字段age,這樣say方法中的姓名、年鄰都有了改變
public Ren(int age, string name)
{
this.age = age;
this.name = name;
Console.WriteLine("哦!你給我起名字,告訴我多大了吧!你說的算!");
Say();
}
//定義靜態的構造函數,我把她放在在最後,但是會第一個被調用。
static Ren()
{
Console.WriteLine("我是靜態的構造函數,不能有參數及訪問修飾符,並且創建對象時,我只執行一次,最先調用");
Console.WriteLine();
}
}
class Program
{
static void Main(string[] args)
{
//創建無參的對象boby,並且創建時會先調用靜態的構造方法,再調用無參的構造方法
Ren boby = new Ren();
Console.WriteLine();
//創建有姓名參數的對象songer歌手
Ren songer = new Ren("周杰倫");
Console.WriteLine();
//創建有年齡、姓名參數的對象man
Ren man = new Ren(33,"貝克漢姆");
Console.WriteLine();
}
}
}
結果如下:
我是靜態的構造函數,不能有參數及訪問修飾符,並且創建對象時,我只執行一次,最先調用
我剛出生!還沒有名字,年齡也從0歲開始!
我的年齡:0,我的名字:,我的性別:女
呦!我使用雙截棍,我有名字了!,但是年齡呢?,我自己定,我就27歲了。
我的年齡:27,我的名字:周杰倫,我的性別:男
哦!你給我起名字,告訴我多大了吧!你說的算!
我的年齡:33,我的名字:貝克漢姆,我的性別:男
滅亡了
滅亡了
滅亡了
請按任意鍵繼續. . .
--------------------------------------------------------------------------------
因爲析構方法比較好理解,看這個實例同學們就能明白他的用法,析構函數的繼承順序是按照從派生程度最大到最小的順序調用的,也就是與構造方法繼承順序相反,先結束子類的析構方法,再結束爸爸類的,再結束爺爺類的,這點也比較好理解,可以把構造方法和析構方法看出一對開始和結束的標記,內部的開始標記最先結束,最外部的開始標記,最後結束。
本節課我們就學到這裏,下節課我們來學習類的六大分類。
本文出自 “葉子文文” 博客,轉載請與作者聯繫!
本文出自 51CTO.COM技術博客
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.