11-3 關鍵字 this、static 的使用

類別是物件的藍圖,每一個物件實例都是依據類別中的定義來建立,物件擁有自己的一份變數(資料成員),但是對於方法成員卻是共用的,為了區別呼叫方法時是使用哪一個物件的變數資料,方法呼叫時會隱含 this 參考名稱。

另一方面,您也可以將變數或方法設定為 static,稱之為靜態成員( Static member ),靜態成員屬於類別所有,呼叫靜態方法時不會有 this 參考名稱,所以靜態方法中不可以有非靜態變數,或呼叫非靜態方法。

• this 參考名稱

以程式碼 11-1 而言,如果您使用以下的程式碼片段實例化兩個物件:

Hello hello1 = new Hello("Java");
Hello hello2 = new Hello("Duke");
                            

則 hello1 與 hello2 所參考的物件,實際上會各自擁有自己的一份 name 成員,但是方法則是共用的。

圖11-10 物件擁有自己的一份資料成員

當物件呼叫方法時,它們會呼叫共用的方法成員,但方法成員中如果有物件的資料成員的話,如何確認是哪一個物件所擁有的呢?答案是物件會告訴方法一個 this 參考名稱。

每一次物件呼叫共用的方法時,隱含的都會傳遞給方法一個this 參考名稱,這個名稱會參考至物件本身,舉個例子來說,程式碼 11-1 的 hello()方法片段:

public void hello() {
    System.out.print("Hello ");
    System.out.println(name);
}
                            

實際上在呼叫執行時會是執行這個程式片段:

public void hello() {
    System.out.print("Hello ");
    System.out.println(this.name);
}
                            

假設 hello1 呼叫 hello()方法,則 this 所參考的物件就是 hello1 所參考的物件,因而知道所使用的 name 成員就是 hello1 所參考物件的 name 成員;同樣的,如果 hello2 呼叫 hello() 方法,this 所參考的物件就是 hello2 所參考的物件,所以也可以正確的存取到 hello2 的 name 成員。

圖11-11 藉由 this 正確存取物件的資料成員

必要的話,您可以明確在程式中撰寫 this,這表示您要使用的是物件自己的成員,例如當類別變數名稱與方法上的參數名稱相同時,為了避免參數的作用範圍覆蓋了類別變數的作用範圍,您要明確指定 this,直接改寫一下程式碼 11-1 為程式碼 11-6 作為示範。

public class Hello2{
    private String name;

    public Hello2(){
        name = "nobody";
    }

    public Hello2(String name){
        this.name = name;
    }

    public void hello(){
        System.out.print("Hello ");
        System.out.println(this.name);
    }

    public void setName(String name){
        this.name = name;
    }
}
                            
程式碼 11-6 Hello2.java

在程式碼的第 8 行到第 10 行,由於參數名稱為類別變數名稱都是 name,為了區別兩者,在類別變數名稱上明確指定this 參考,表示這個 name 會是物件自己的資料成員,藉此與參數名稱作區別,第 17 行到第 19 行也是相同的作用。

this 可以有一種帶參數的呼叫方法,作用為呼叫類別中的建構方法,例如:

public class Hello3{
    private String name;

    public Hello3(){
        this("nobody");
    }

    public Hello3(String name){
        this.name = name;
    }

    public void hello(){
        System.out.print("Hello ");
        System.out.println(this.name);
    }

    public void setName(String name){
        this.name = name;
    }
}
                            
程式碼 11-7 Hello3.java

當使用預設建構式時,this("nobody")將呼叫對應的參數建構式,也就是執行第 8 行至第 10 行。

• static 成員

靜態成員是類別層次所擁有的成員,您可以使用關鍵字 static 來將成員修飾為靜態成員,例如:

public class SimpleMath{
    public static final double PI = 3.141596;
    public static double
                    circumference(double r){
        return PI * r * r;
    }

    public static double area(double r){
        return PI * r * r;
    }

    public static double volumn(double r){
        return PI * r * r * r * 4 / 3;
    }
}
                            
程式碼 11-8 SimpleMath.java

您可以直接使用類別名稱加上 . 運算子來存取靜態資料成員,例如下面的程式片段將印出 3.141596:

System.out.println("PI = " + SimpleMath.PI);
                            

靜態方法的呼叫也是直接使用類別名稱加上 . 運算子,例如:

System.out.println("圓周長:"
    + SimpleMath. circumference(2.1));
System.out.println("圓面積:"
    + SimpleMath.area(2.1));
System.out.println("球體積:"
    + SimpleMath.volumn(2.1));
                            

之前單元介紹過 Integer 等 Wrapper 類別上,擁有一些剖析方法,像是 Integer.parseInt()就是類別上的靜態方法,所以您可以了解到,靜態方法通常作為類別所提供的工具方法,透過類別名稱來管理與取用這些靜態資料或方法。

由於 static 成員是屬於類別所擁有,所以呼叫 static 的方法時,不會傳入 this 參考名稱,因而在 static 方法中不能有非static 的資料成員,因為沒有 this 名稱可以辨別到底是哪一個物件的資料成員,如果您在靜態方法中嘗試存取非靜態資料成員,則編譯時就會出現以下的錯誤:

non-static variable test cannot be referenced from a static context
                            

在 static 方法中,也不可以呼叫非 static 的方法,否則編譯時會出現以下的錯誤:

non-static method somemethod() cannot be referenced from a static context