Thinking in Java(4-1) 建構子與物件初始化

Thinking in Java(4-1) 建構子與物件初始化
Photo by orbtal media / Unsplash

使用建構子確保初始化

基本概念

  • 當你想要初始化一個類別時,可能會想到在每個類別中定義一個假設的 initialize() 方法。但這要求每個使用者都記得手動呼叫這個方法,容易出錯。
  • 透過使用建構子,我們可以確保每個物件在建立時自動初始化。
  • Java 在建立物件時,會自動呼叫與類別名稱相同的建構子,編譯器因此知道如何進行初始化。
  • 建構子的名稱必須與類別名稱完全一致,並且不適用通常方法名稱首字母小寫的命名風格。

範例說明

預設建構子範例

class Rock {
  Rock() { // This is the constructor
    System.out.print("Rock ");
  }
}

public class SimpleConstructor {
  public static void main(String[] args) {
    for(int i = 0; i < 10; i++)
      new Rock();
  }
} /* Output:
Rock Rock Rock Rock Rock Rock Rock Rock Rock Rock
*/
  • 使用 new Rock(); 創建物件時,Java 會為物件分配記憶體並呼叫其建構子
  • 未接收任何參數的建構子稱為預設建構子。在 Java 文件中,這類建構子常被稱為無參數建構子(no-arg constructor)。

帶參數建構子範例

  • 透過對建構子稍加修改,我們可以使其接受參數,從而根據這些參數進行更為定制化的初始化操作。
class Rock2 {
  Rock2(int i) {
    System.out.print("Rock " + i + " ");
  }
}

public class SimpleConstructor2 {
  public static void main(String[] args) {
    for(int i = 0; i < 8; i++)
      new Rock2(i);
  }
} /* Output:
Rock 0 Rock 1 Rock 2 Rock 3 Rock 4 Rock 5 Rock 6 Rock 7
*/
  • 建構子不允許有任何返回型態,甚至包括 void。這是因為建構子的主要目的在於初始化物件,而非計算值或返回資料。如果在建構子定義中加入返回型態,會導致編譯錯誤。

方法多載(Method Overloading)

  • 在 Java 中,相同名稱的方法可以有不同的實現,這種設計主要是為了減少冗餘。例如,"洗"這個動作可以用於洗衣服、洗車或洗狗。若每種情況都設立一個獨立的方法名稱,將會非常冗餘。
  • 方法多載允許相同的方法名稱在同一個類別中以不同的參數列表存在,這樣可以根據傳入參數的不同,調用相對應的方法。
class Tree {
  int height;
  Tree() {
    print("Planting a seedling");
    height = 0;
  }
  Tree(int initialHeight) {
    height = initialHeight;
    print("Creating new Tree that is " +
      height + " feet tall");
  }	
  void info() {
    print("Tree is " + height + " feet tall");
  }
  void info(String s) {
    print(s + ": Tree is " + height + " feet tall");
  }
}

public class Overloading {
  public static void main(String[] args) {
    for(int i = 0; i < 5; i++) {
      Tree t = new Tree(i);
      t.info();
      t.info("overloaded method");
    }
    // Overloaded constructor:
    new Tree();
  }	
} /* Output:
Creating new Tree that is 0 feet tall
Tree is 0 feet tall
overloaded method: Tree is 0 feet tall
Creating new Tree that is 1 feet tall
Tree is 1 feet tall
overloaded method: Tree is 1 feet tall
Creating new Tree that is 2 feet tall
Tree is 2 feet tall
overloaded method: Tree is 2 feet tall
Creating new Tree that is 3 feet tall
Tree is 3 feet tall
overloaded method: Tree is 3 feet tall
Creating new Tree that is 4 feet tall
Tree is 4 feet tall
overloaded method: Tree is 4 feet tall
Planting a seedling
*/
  • 在這個範例中,Tree 類別提供了兩種建構子:一種不接受參數,另一種接受一個整數參數。
  • 對明顯相同的操作使用兩個不同的名稱會讓人疑惑,有了多載,可以使用相同的名稱。
    • 例如範例中的 info() 方法:一種不接受任何參數,另一種接受一個字串參數。

區分多載的方法

  • 每個多載的方法必須具有獨一無二的參數列表,包括參數的數量、型態或參數的排列順序。
  • 參數順序的變更雖然技術上可行以區分多載方法,但可能造成程式碼難以維護。

使用基本型態的多載

  • 數值常數(如 5)預設被處理為 int 型態。
  • 若傳入的資料型態小於方法所需的參數型態,則會進行型態提升;例如,char 型態若無匹配方法,會提升至 int
  • 如果傳入的數值型態比方法參數大,且沒有適當的型態轉換,將導致編譯錯誤。

根據返回值的多載

  • Java 不支援僅憑返回值不同來多載方法。因為在呼叫時,單憑方法名稱和參數,無法確定應調用哪個方法,特別是在不關心返回值的情況下。
    • 有時可能為了副作用而調用方法,而不關心返回值,例如只調用 f();,即使方法定義了返回值,編譯器也無法判斷要使用哪個多載的方法。

預設建構子(Default Constructors)

基本概念

  • 在 Java 中,如果一個類別沒有明確定義任何建構子,則編譯器會自動為該類別創建一個無參數的預設建構子。這個自動生成的建構子不會執行任何特殊操作,僅僅是允許建立該類別的實例。
  • 這個自動產生的建構子通常被稱為無參數建構子(no-arg constructor)。

條件限制

  • 如果類別中已經明確定義了至少一個建構子(無論該建構子是否接受參數),則編譯器不會自動生成預設建構子。
  • 這意味著,如果你已經定義了一個或多個帶參數的建構子而沒有定義無參數的建構子,嘗試無參數建立實例(即使用 new ClassName();)將導致編譯錯誤。