不學 JAVA 換學 C# 之覺得心累 - L1:ch9 類別和物件 (一)
前言
類別 (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 | // 存取修飾詞:public, class 保留字, 類別名稱:Dog |
建立 Object
是類別的實例 (Instance),是類別具體化後的表現。使用 new
關鍵字,搭配呼叫建構式實例化 (Instantiation) 物件:
1 | Dog lucky = new Dog("哈士奇", "中型犬", "黑白"); |
一旦 Object 被建立了,系統才會分配記憶體空間給 Object,用來儲存它的變動過的特徵以及執行功能後產生的一些結果。
建構式 (Constructor)
是一種特殊的函式,當你建立物件的時候,它會自動執行,用來初始化物件的屬性或執行一些設定,沒有回傳型態。
必須要有建構式,才能用 new
實體化物件,所以如果不寫建構式,C# 會自動提供預設建構式,也可以自訂。
預設建構式 (Default Constructor)
如果沒有定義建構式,C# 會提供一個隱藏的預設建構式 (不做任何初始化)。硬要寫出來的話是長這樣:
1 | // 存取修飾詞:public, 建構式名稱:Dog, 參數列表:() |
對應的實例化程式碼:
1 | // 實體化物件 |
複寫預設建構式
所有使用 new
實體化的狗,都會是哈士奇品種。
1 | public Dog() |
自訂建構式
但是記住,一旦 Class 中寫了一個以上的建構式,預設建構式就會消失。
1 | public Dog(string breed, string size) |
特殊且唯一的 C# 的類別
僅包含 Main()
方法的類別,是應用程式的進入點,請參考不學 JAVA 換學 C# 之覺得心累 - L1:ch0 程式架構。
關鍵字 this
代表目前這個類別的物件本身,可以用來:
- 存取目前物件的欄位或方法
- 區分欄位和參數同名的情況 (如果不會混淆也可以不用寫出
this
) - 建構式去呼叫在同一個 Class 中的另一個建構式 (constructor chaining)
區分欄位和參數
1 | public class Dog |
建構式去呼叫在同一個 Class 中的另一個建構式
使用 this
來重複使用建構式的邏輯:line 6 的 this("哈士奇", "中型犬")
和 line 8 的 this(breed, "大小未知")
去呼叫 line 10 的建構式。
建構式中的任何參數,都可以作為this
的參數來使用或運算:line 8 public Dog(string breed)
的參數 breed
作為傳入 this
的參數 this(breed, "大小未知")
。
1 | public class Dog |
靜態修飾詞 static
如果欄位跟各別物件實例沒有關係,就用靜態欄位,否則用非靜態欄位。
非靜態欄位
非靜態欄位屬於物件,必須透過實例化物件來呼叫,且不同物件的非靜態欄位互不影響。使用物件名稱呼叫。
1 | 物件名稱.欄位名; |
以下方例子來說,不同的實例化物件 Person
有不同的名字。
1 | public class Person |
靜態欄位
靜態欄位屬於類別本身,不需實例化物件即可呼叫。適合用於不依賴於物件狀態的欄位。使用類別名稱呼叫。
1 | 類別名稱.欄位名; |
特性
- 所有物件共用同一份欄位值。
- 建立物件前就可以使用。
以下方例子來說,PI
不會依賴於不同的 Example
物件實例,直接用 Example
類別名呼叫 PI
。
1 | public class Example |
也去看看非靜態方法和靜態方法吧!
欄位的常數 const
和 readonly
常數 const
是編譯階段常數 (compile-time constant),又稱為靜態常數,也就是在程式編譯的當下,這個值就已經是確定的、固定好的,並且直接寫進程式碼裡 (在 .exe 或 .dll 裡),因此必須在宣告時就初始化,這個值不能在程式執行時才被指派。又因為直接寫進程式碼裡,因此沒有占用記憶體,效能較快,使用時也是直接引用其值。
只有數值、布林、字串可以被指定為 const
常數。物件的參考類型也可以被指定為 const
常數,但是只能指定為 null
(但這好像沒什麼意義 …)。
命名規則是全部使用大寫,並且以下底線 _
隔開,方便辨識。全部大寫可以輕易地與一般變數做出區別。
1 | public const double PI = 3.1415; |
類別中的 const
永遠有 static
的特性,但是加 static
會報錯 (不能這樣寫: static const
)。
常數 readonly
是執行階段常數 (run-time constant),又稱為動態常數,在執行時才獲得實際的數值,可以在宣告時或建構式中初始化,而且在建構式中可以重複指派,不能宣告在方法裡做為區域變數。使用時是像一般變數一樣,引用記憶體位置的值。其實就是唯獨的變數啦!
1 | public class Example |
特性 | const |
readonly |
---|---|---|
類別 | 編譯階段常數,直接引用其值 | 執行階段常數,或唯獨變數,引用記憶體位置的值 |
宣告時機 | 必須在宣告時就初始化 | 可以在宣告時或建構式中初始化 |
變更時機 | 無法更改 | 在建構式中可以重複指派 |
每個物件有屬於自己的常數 | 不行,所有物件共用同一個 const 常數 (像是 static 變數) |
可以,每個物件可以在建構時,依據呼叫不同的建構式設定不同值 |
使用場景 | 固定值 (例如:PI) | 需在執行期間決定,但不希望被更改的值(例如:DbContext) |
是否為 static | 永遠隱含 static 的特性 |
不是 static ,除非明確宣告 static readonly |