2009年7月23日 星期四

What is “this”?

What is “this”?這是許多物件導向程式語言初學者的疑問。
在許多物件導向語言中都存在著「this」關鍵字,舉凡Java、C++、C#都有這樣一個謎一般的關鍵字,在VB.Net與Ruby中則是以「self」之名存在著。某些非物件導向的程式語言如Javascript,甚至也提供「this」來模擬物件導向的特性。
究竟「this」是天使的化身,還是地獄的使者?是什麼樣的力量促使他在物件導向的世界裡屹立不搖?其實,它沒那麼偉大,充其量只是個「第一人稱代名詞」。
在解釋它存在的必要之前,我們必須先為一個人生難題找出解答:如何在不說「我」的情況下,用合理的文法表達「教授把我當了」?如果你說「教授把XXX當了」,這樣的句子很奇怪,像是說另一個和你同名同姓還被你爆料的可憐同學。如果你說「教授當了」,請問教授到底當了誰?如果你說「被教授當了」,聽起來合理,但這其實是把「我」省略的慣用句型,文法上不合理,因為缺乏主詞。
不知道有沒有人可以找出答案,如果有請留言告訴我。無論如何,代名詞不是我的重點,我只是想證實第一人稱代名詞的必要性:若沒有第一人稱代名詞,我們很難用語言表達自己的存在,也很難做第一人稱敘述。
在物件導向的世界裡也是一樣的。由於一個類別可以產生許多實體,就必須用一個代名詞來讓個別實體表達「我」,以區分和其他實體的不同。一個類別的實體就是用「this」表達「我」。

例如以下程式碼:
class Student{
private int score;
Student(int s){
score = s; //A
}
public void say(){
if( this.score > 59) // B
System.out.println("教授讓我過了!");
else
System.out.println("教授把我當了!");
}
public static void main(String[] arg){
Student 好學生 = new Student(80);
Student 混學生 = new Student(40);
好學生.say();
混學生.say();
}
}

在main中,產生兩個Student類別的實體,兩個實體say的結果不一樣,因為this.score的值不一樣。這樣就可以看出,每個new出來的實體都有自己的this,代表各自的實體。

※B的this是可以省略的,因為是在同一個類別,Java編譯器會在編譯時自動加入this。如A的score也可以改為this.score。

其實看下圖就一目了然:



main方法的Stack Frame中,「好學生」與「混學生」參照分別參考到不同的Student實體,兩個Student實體的this參照也分別參考到自己從屬的實體。如此一來,每個實體就可以用this表達「我」。例如,我的score就是this.score。
那麼你可能會有個疑惑:難道「this」存在的意義只是為了表達像this.score這種可以省略的語法嗎?「this」真正的好處在於,實體可以將自己傳遞給其他實體。

為了解釋這點,我們定義一個Professor類別,並在Student類別裡加入getScore方法,如下:
class Professor{
public void grade(Student student){
student.score = (int)(Math.random()*101);
}
}
class Student{
...
Professor 叫獸 = new Professor();
public int getScore(){
叫獸.grade(this); // C
return score;
}

public static void main(String[] arg){
Student 羔羊 = new Student(0);
羔羊.getScore();
羔羊.say();
}
}

我們先產生一個Student的實體「羔羊」,並呼叫getScore方法。呼叫時,羔羊的實體就會傳入叫獸.grade()方法,並設定score。C的部分,就是Student實體將自身傳入叫獸.grade()方法的部分。其實這行程式碼,翻成中文就是「叫獸給我打分數。」「this」就是「我」!

沒有留言:

張貼留言