Thinking in Java(4-2) 深入理解 Java 中的 this 關鍵字與 static 方法

Thinking in Java(4-2) 深入理解 Java 中的 this 關鍵字與 static 方法
Photo by orbtal media / Unsplash

在 Java 程式設計中,this 關鍵字和 static 方法是兩個重要的概念。本篇文章將深入探討它們的用途和特性,並透過範例說明如何在實際程式中應用。

this 關鍵字的用途

多個相同類型的物件調用方法

假設我們有兩個同類型的物件 ab

public class BananaPeel {
  public static void main(String[] args) {
    Banana a = new Banana(),
           b = new Banana();
    a.peel(1);
    b.peel(2);
  }
}

在上述程式中,我們如何知道 peel() 方法是被 a 還是 b 調用的呢?

為了以物件導向的方式簡潔地編寫程式,編譯器在幕後做了一些工作:它將「所操作物件的參考」作為第一個參數傳遞給 peel() 方法。

換句話說,編譯器實際上將程式轉換成如下形式:

Banana.peel(a, 1);
Banana.peel(b, 2);
注意:以上寫法只是為了說明原理,實際上我們不能這樣寫。

由於這個參考是由編譯器「偷偷」加上的,因此在方法內部沒有顯式的標識。為此,Java 提供了專門的關鍵字 this

  • this 關鍵字在方法內部代表當前物件的參考。
  • this 只能在方法內使用,與其他物件的參考並無不同。
  • 在方法內調用另一個物件的方法時,通常不需要使用 this

方法內調用其他方法

考慮以下範例:

public class Apricot {
  void pick() { /* ... */ }
  void pit() { pick(); /* ... */ }
}

pit() 方法內,我們可以寫成 this.pick(),但沒必要,因為編譯器會自動添加 this

只有在需要明確指出當前物件時,才需要使用 this,例如當我們需要返回當前物件的參考時:

public class Leaf {
  int i = 0;
  Leaf increment() {
    i++;
    return this;
  }
  void print() {
    System.out.println("i = " + i);
  }
  public static void main(String[] args) {
    Leaf x = new Leaf();
    x.increment().increment().increment().print();
  }
} /* Output:
i = 3
*/

在上述程式中,increment() 方法返回 this,使我們可以鏈式調用該方法。

將當前物件傳遞給其他方法

當我們需要將當前物件傳遞給其他方法時,this 也非常有用:

class Person {
  public void eat(Apple apple) {
    Apple peeled = apple.getPeeled();
    System.out.println("Yummy");
  }
}

class Peeler {
  static Apple peel(Apple apple) {
    // ... remove peel
    return apple; // Peeled
  }
}

class Apple {
  Apple getPeeled() { return Peeler.peel(this); }
}

public class PassingThis {
  public static void main(String[] args) {
    new Person().eat(new Apple());
  }
} /* Output:
Yummy
*/

在這個範例中,Apple 物件透過 this 將自己傳遞給 Peeler.peel() 方法。

在建構子中調用其他建構子

在建構子中,如果我們使用 this 並附帶參數列表,會產生對符合該參數列表的另一個建構子的明確調用。

public class Flower {
  int petalCount = 0;
  String s = "initial value";
  Flower(int petals) {
    petalCount = petals;
    print("Constructor w/ int arg only, petalCount= "
      + petalCount);
  }
  Flower(String ss) {
    print("Constructor w/ String arg only, s = " + ss);
    s = ss;
  }
  Flower(String s, int petals) {
    this(petals);
	//!    this(s); // Can't call two!
    this.s = s; // Another use of "this"
    print("String & int args");
  }
  Flower() {
    this("hi", 47);
    print("default constructor (no args)");
  }
  void printPetalCount() {
	//! this(11); // Not inside non-constructor!
    print("petalCount = " + petalCount + " s = "+ s);
  }
  public static void main(String[] args) {
    Flower x = new Flower();
    x.printPetalCount();
  }
} /* Output:
Constructor w/ int arg only, petalCount= 47
String & int args
default constructor (no args)
petalCount = 47 s = hi
*/

注意事項

  • 可以使用 this 調用另一個建構子,但不能同時調用多個。
  • 必須將建構子的調用放在當前建構子的第一行,否則編譯器會報錯。
  • 在非建構子的方法中,不能使用 this 調用建構子。

static 的概念

  • static 方法是沒有 this 的方法,只能訪問其他 static 方法和 static 屬性。
  • static 方法可以在沒有任何物件實例的情況下,透過類別本身調用。
  • Java 不允許使用全域方法,但我們可以在類別中定義 static 方法,來模擬全域方法的效果。

範例

public class StaticExample {
  static int staticValue = 5;
  
  static void staticMethod() {
    System.out.println("Static method called. staticValue = " + staticValue);
  }
  
  public static void main(String[] args) {
    StaticExample.staticMethod();
  }
} /* Output:
Static method called. staticValue = 5
*/

在這個範例中,我們直接使用類別名調用 staticMethod(),而不需要創建物件實例。

總結

this 關鍵字在 Java 中扮演著重要的角色,使我們能夠在物件導向的程式設計中精確地操作和傳遞當前物件。它在方法和建構子中都有廣泛的應用。

另一方面,static 方法和屬性則提供了在沒有物件實例的情況下,共享資料和行為的方式。理解這兩個概念有助於我們更有效地編寫 Java 程式。