類別是物件的藍圖,每一個物件實例都是依據類別中的定義來建立,物件擁有自己的一份變數(資料成員),但是對於方法成員卻是共用的,為了區別呼叫方法時是使用哪一個物件的變數資料,方法呼叫時會隱含 this 參考名稱。
另一方面,您也可以將變數或方法設定為 static,稱之為靜態成員( Static member ),靜態成員屬於類別所有,呼叫靜態方法時不會有 this 參考名稱,所以靜態方法中不可以有非靜態變數,或呼叫非靜態方法。
以程式碼 11-1 而言,如果您使用以下的程式碼片段實例化兩個物件:
Hello hello1 = new Hello("Java"); Hello hello2 = new Hello("Duke");
則 hello1 與 hello2 所參考的物件,實際上會各自擁有自己的一份 name 成員,但是方法則是共用的。
當物件呼叫方法時,它們會呼叫共用的方法成員,但方法成員中如果有物件的資料成員的話,如何確認是哪一個物件所擁有的呢?答案是物件會告訴方法一個 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 成員。
必要的話,您可以明確在程式中撰寫 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 來將成員修飾為靜態成員,例如:
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