CodeGym /課程 /C# SELF /類別與物件:建立、建構子與初始化

類別與物件:建立、建構子與初始化

C# SELF
等級 12, 課堂 0
開放

1. 建立物件

我們終於來到物件的建立啦。你之前應該已經碰過這個,只是現在我們要更仔細地聊聊。其實建立物件超簡單的。

要建立物件,你要用 new 運算子。通常你會建立一個 class 的新實例(物件),然後馬上把它存到同型別的變數裡。

類別 名稱 = new 類別(參數);
建立物件的語法

這裡 類別 是物件的型別,名稱 是變數名稱(通常小寫開頭,比如 cat),而 = 右邊就是建立這個 class 的新物件。

範例:

程式碼 說明
object o = new object();
建立 object 型別的物件
Cat pet = new Cat();
建立 Cat 型別的物件
var reader = new StreamReader("file.txt");
建立帶參數的 StreamReader 物件

很常見的寫法是,程式設計師會把變數名稱取成跟 class 一樣,只是小寫開頭。新手看到這種寫法可能會有點混亂:

程式碼
Student student = new Student();
Car car = new Car();
PersonInfo personInfo = new PersonInfo();

其實這種寫法完全沒問題——就是很普通的程式碼,建立一個變數,然後馬上用同型別的物件初始化它。

左邊是變數宣告,右邊是用 new 在記憶體裡建立新物件。就這樣!

2. 建構子

你應該常常看到,建立物件時會傳一些參數進去。有些物件要參數,有些不用。那這個參數機制到底怎麼運作?

這也很簡單:每個 class 都有一個(或多個)特別的方法,專門處理建立物件時的參數。這種方法叫 建構子。一個方法就是 建構子

要分辨建構子跟一般方法很簡單。建構子有兩個特點:

  • 建構子的名稱跟 class 名稱一樣(而且大寫開頭)
  • 建構子沒有回傳型別(連 void 都不用寫)。

一般語法長這樣:


修飾詞 類別(參數)
{
   建構子程式碼
}
建構子的語法

建構子宣告範例:

public class Point
{
    public int X;
    public int Y;

    public Point(int x, int y) // 建構子
    {
        X = x;
        Y = y;
    }
}

用法:

Point p = new Point(5, 10); // 呼叫建構子

new Point(5, 10) 建立物件時,會呼叫帶兩個參數的建構子,初始化 XY 欄位。

有時候建構子的參數名稱會跟欄位一樣——這樣比較方便。這種名稱衝突可以用 關鍵字 this 解決:

public Point(int x, int y)
{
    this.x = x; // this.x 是物件欄位,x 是建構子的參數
    this.y = y;
}

3. 呼叫建構子

當你寫 new 類別(參數),C# 會:

  • 在記憶體裡建立新物件,
  • 呼叫對應的建構子,把你的參數傳進去。

以貓咪 class 為例:

public class Cat
{
    public string Name;
    public int Age;

    public Cat(string name, int age)
    {
        Name = name;
        Age = age;
    }
}

用法:

Cat cat = new Cat("瓦斯卡", 2); // OK:呼叫帶兩個參數的建構子
Cat cat2 = new Cat("瓦斯卡");   // 不行:沒有這種建構子——編譯錯誤
Cat cat3 = new Cat();           // 不行:沒有無參數建構子——編譯錯誤

如果 class 只有帶參數的建構子,你就必須在建立物件時給它參數。

4. 多個建構子

不過如果你想,也可以在 class 裡加很多個建構子。建構子的數量跟參數沒有限制。建立物件時,編譯器會自動挑對應參數的建構子。

範例:

public class Cat
{
    public const int UNKNOWN = -1;
    public string Name;
    public int Age;

    public Cat(string name, int age)
    {
        Name = name;
        Age = age;
    }

    public Cat(string name)
    {
        Name = name;
        Age = UNKNOWN; // 年齡未知時的預設值
    }
}

用法:

Cat cat1 = new Cat("瓦斯卡", 2); // 用第一個建構子
Cat cat2 = new Cat("穆卡");     // 用第二個建構子
Cat cat3 = new Cat();            // 錯誤!沒有無參數建構子

我們考慮到有時候貓的年齡可能不知道。這時就加了一個常數 UNKNOWN,還有一個只需要名字的建構子。

注意,我們還是會在兩個建構子裡初始化所有 class 變數。缺的參數就用 UNKNOWN 代替。

5. 預設建構子

如果你的 class 沒有任何建構子,編譯器會自動加上一個空的無參數建構子:


public ClassName()
{
}
預設建構子的語法

但如果 class 裡已經有自己宣告的建構子——就不會自動加空建構子了

範例 1:

public class Cat
{
    public string Name;
    public int Age;
}

// 可以:
Cat cat = new Cat(); // 會呼叫預設建構子(無參數)

範例 2:

public class Cat
{
    public string Name;
    public int Age;

    public Cat(string name) { Name = name; }
}

// 不行:
Cat cat = new Cat(); // 錯誤:沒有無參數建構子了!

6. 變數初始化

在 C# 裡,class 變數可以直接在宣告時初始化,也可以在建構子裡初始化。

範例:

public class Cat
{
    public string Name;
    public int Age = -1; // 初始值

    public Cat(string name, int age)
    {
        Name = name;
        Age = age; // 覆蓋初始值
    }

    public Cat()
    {
        Name = "無名";
        // Age 還是 -1(初始值)
    }
}

說明:

  • new Cat("瓦斯卡", 2) 建立時,Age 先是 -1,但建構子會把它改成 2
  • new Cat() 建立時,Age 會保持 -1

7. 變數初始化順序

新物件的資料初始化順序如下:

  1. class 欄位 先拿到預設值(0intnull 給參考型別等等)。
  2. 然後執行你在欄位宣告時寫的初始化器,照程式碼出現順序。
  3. 最後才執行建構子的程式碼。

變數會在建構子之前照宣告順序初始化。所以欄位之間有依賴關係時要小心。

錯誤範例

非 static 欄位不能用其他非 static 變數初始化:


public class Solution
{
    public int a = 1; 
    public int b = a;        // 不能用 a
    public int c = a + b;   // 不能用 a 跟 b
}
// 這樣會編譯錯誤!
錯誤:非 static 欄位初始化時不能互相參考

正確範例

對 static 變數來說,這樣就沒問題

public class Solution
{
    public static int a = 1;          // 明確設定 a = 1
    public static int b = a + 2;      // b = 1 + 2 ⇒ 3
    public static int c = a + b + 3;  // c = 1 + 3 + 3 ⇒ 7

    public Solution()
    {
        Console.WriteLine($"a = {a}, b = {b}, c = {c}");
        // 會印出:a = 1, b = 3, c = 7 —— 就是預期的結果
    }
}
static 欄位初始化

正確範例 2

static 欄位甚至可以這樣寫:

public class Solution
{
    public static int a = b + c + 1;    // b 跟 c 還是 0
    public static int b = a + c + 2;    // a == 1, c 還是 0
    public static int c = a + b + 3;    // a == 1, b == 3
}
static 欄位與初始化順序
2
任務
C# SELF, 等級 12, 課堂 0
上鎖
建立類別與物件
建立類別與物件
2
任務
C# SELF, 等級 12, 課堂 0
上鎖
變數初始化與多個建構子
變數初始化與多個建構子
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION