不學 JAVA 換學 C# 之覺得心累 - L1:ch9 類別和物件 (一)

AdSense

前言

類別 (Class) 與物件 (Object) 是 C# 的基礎核心,基於物件導向程式設計 (OOP,Object Oriented Programming) 的特性,讓開發者能建立可重複使用且維護性高的程式碼。

物件導向

Class 類別

Class 類別是設計藍圖模具產品規格,它主要用來定義一個產品的特徵 (欄位 Field、屬性 Property) 和功能 (方法 Method)。

Object 物件、Instance 實例

利用產品規格產生出來的實品,每個實品可能有特徵或功能上的不同,但都是類別具體化後的表現。

簡單來說,Class 就是產品規格、Object 就是製作出來的實品。

建立類別與物件

建立 Class

類別包含欄位 Field、屬性 Property、建構式 Constructor 與方法 Method,定義了物件的狀態與行為,可使用不同的存取修飾詞控制存取範圍。

  • 欄位 Field、屬性 Property:定義物件的狀態和特徵。(如:狗的品種、大小。)
  • 建構式 Constructor:用於建立物件,產生基礎的物件狀態。(如:創造一隻狗的時候,它要被設定品種、大小和顏色。)
  • 方法 Method:定義物件的行為。(如:狗的叫聲、奔跑方式。)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 存取修飾詞:public, class 保留字, 類別名稱:Dog
public class Dog
{
// 欄位 Field
public string breed;
public string size;
public string color;

// 建構式 Constructor
public Dog(string breed, string size, string color)
{
this.breed = breed;
this.size = size;
this.color = color;
}

// 方法 Method
public void Bark() {
Console.WriteLine("汪!汪!汪!");
}
}

建立 Object

是類別的實例 (Instance),是類別具體化後的表現。使用 new 關鍵字,搭配呼叫建構式實例化 (Instantiation) 物件

1
2
Dog lucky = new Dog("哈士奇", "中型犬", "黑白");
lucky.Bark(); // 輸出:汪!汪!汪!

一旦 Object 被建立了,系統才會分配記憶體空間給 Object,用來儲存它的變動過的特徵以及執行功能後產生的一些結果

建構式 (Constructor)

是一種特殊的函式,當你建立物件的時候,它會自動執行,用來初始化物件的屬性或執行一些設定,沒有回傳型態

必須要有建構式,才能用 new 實體化物件,所以如果不寫建構式,C# 會自動提供預設建構式,也可以自訂。

預設建構式 (Default Constructor)

如果沒有定義建構式,C# 會提供一個隱藏的預設建構式 (不做任何初始化)。硬要寫出來的話是長這樣:

1
2
3
// 存取修飾詞:public, 建構式名稱:Dog, 參數列表:()
public Dog()
{}

對應的實例化程式碼:

1
2
// 實體化物件
Dog lucky = new Dog();

複寫預設建構式

所有使用 new 實體化的狗,都會是哈士奇品種。

1
2
3
4
5
6
public Dog()
{
this.breed = "哈士奇";
}

Dog lucky = new Dog();

自訂建構式

但是記住,一旦 Class 中寫了一個以上的建構式,預設建構式就會消失。

1
2
3
4
5
6
7
8
public Dog(string breed, string size)
{
this.breed = breed;
this.size = size;
}

Dog lucky = new Dog("紅貴賓", "小型犬"); // 必須用自訂的建構式建立物件
// Dog coby = new Dog(); // 這行會報錯,因為預設建構式已經消失

特殊且唯一的 C# 的類別

僅包含 Main() 方法的類別,是應用程式的進入點,請參考不學 JAVA 換學 C# 之覺得心累 - L1:ch0 程式架構

關鍵字 this

代表目前這個類別的物件本身,可以用來:

  1. 存取目前物件的欄位或方法
  2. 區分欄位和參數同名的情況 (如果不會混淆也可以不用寫出 this)
  3. 建構式去呼叫在同一個 Class 中的另一個建構式 (constructor chaining)

區分欄位和參數

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Dog
{
public string breed;
public string size;

public Dog(string breed, string size)
{
// 因為欄位和參數名稱相同,怕會混淆,用 this 指出是物件的 breed 和 size
// 物件欄位 參數
this.breed = breed;
this.size = size;
}
}

建構式去呼叫在同一個 Class 中的另一個建構式

使用 this 來重複使用建構式的邏輯:line 6 的 this("哈士奇", "中型犬") 和 line 8 的 this(breed, "大小未知") 去呼叫 line 10 的建構式。

建構式中的任何參數,都可以作為this 的參數來使用或運算:line 8 public Dog(string breed) 的參數 breed 作為傳入 this 的參數 this(breed, "大小未知")

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Dog
{
public string breed;
public string size;

public Dog() : this("哈士奇", "中型犬")
{}
public Dog(string breed) : this(breed, "大小未知")
{}
public Dog(string breed, string size)
{
this.breed = breed;
this.size = size;
}
}

靜態修飾詞 static

如果欄位跟各別物件實例沒有關係,就用靜態欄位,否則用非靜態欄位。

非靜態欄位

非靜態欄位屬於物件,必須透過實例化物件來呼叫,且不同物件的非靜態欄位互不影響。使用物件名稱呼叫。

1
物件名稱.欄位名;

以下方例子來說,不同的實例化物件 Person 有不同的名字。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Person
{
public string name;

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

Person person1 = new Person("Jenifer");
Person person2 = new Person("Mary");

// 使用物件名稱呼叫 name
Console.WriteLine(person1.name); // Jenifer
Console.WriteLine(person2.name); // Mary

靜態欄位

靜態欄位屬於類別本身,不需實例化物件即可呼叫。適合用於不依賴於物件狀態的欄位。使用類別名稱呼叫。

1
類別名稱.欄位名;

特性

  • 所有物件共用同一份欄位值。
  • 建立物件前就可以使用。

以下方例子來說,PI 不會依賴於不同的 Example 物件實例,直接用 Example 類別名呼叫 PI

1
2
3
4
5
6
7
8
9
public class Example
{
public static double PI = 3.1415;
};

Console.WriteLine(Example.PI); // 3.1415

Example example1 = new Example ();
Example example2 = new Example ();

也去看看非靜態方法和靜態方法吧!

欄位的常數 constreadonly

常數 const

編譯階段常數 (compile-time constant),又稱為靜態常數,也就是在程式編譯的當下,這個值就已經是確定的、固定好的,並且直接寫進程式碼裡 (在 .exe 或 .dll 裡),因此必須在宣告時就初始化,這個值不能在程式執行時才被指派。又因為直接寫進程式碼裡,因此沒有占用記憶體,效能較快,使用時也是直接引用其值

只有數值、布林、字串可以被指定為 const 常數。物件的參考類型也可以被指定為 const 常數,但是只能指定為 null (但這好像沒什麼意義 …)。

命名規則是全部使用大寫,並且以下底線 _ 隔開,方便辨識。全部大寫可以輕易地與一般變數做出區別。

1
2
3
4
public const double PI = 3.1415;
public const boolean CAN_SMOKE = false;
public const string APP_OWNER = "Jenifer";
public const Employee QUITTED_EMPLOYEE = null;

類別中的 const 永遠有 static 的特性,但是加 static 會報錯 (不能這樣寫: static const)。

常數 readonly

執行階段常數 (run-time constant),又稱為動態常數,在執行時才獲得實際的數值,可以在宣告時或建構式中初始化,而且在建構式中可以重複指派,不能宣告在方法裡做為區域變數。使用時是像一般變數一樣,引用記憶體位置的值。其實就是唯獨的變數啦!

1
2
3
4
5
6
7
8
9
public class Example
{
public readonly int num = 3;
public Example ()
{
num = 5;
num = 10;
}
}
特性 const readonly
類別 編譯階段常數,直接引用其值 執行階段常數,或唯獨變數,引用記憶體位置的值
宣告時機 必須在宣告時就初始化 可以在宣告時或建構式中初始化
變更時機 無法更改 在建構式中可以重複指派
每個物件有屬於自己的常數 不行,所有物件共用同一個 const 常數 (像是 static 變數) 可以,每個物件可以在建構時,依據呼叫不同的建構式設定不同值
使用場景 固定值 (例如:PI) 需在執行期間決定,但不希望被更改的值(例如:DbContext)
是否為 static 永遠隱含 static 的特性 不是 static,除非明確宣告 static readonly