使用 this


除了被宣告為static的地方外,this關鍵字可以出現在類別中任何地方,在物件建立後為「這個物件」的參考名稱,目前你看到的應用,就是在建構式參數與物件資料成員同名時,可用this加以區別。

public class CashCard {
    private String number;
    private int balance;
    private int bonus;
    public CashCard(String number, int balance, int bonus) {
        this.number = number;     // 參數number指定給這個物件的number
        this.balance = balance;   // 參數balance指定給這個物件的balance
        this.bonus = bonus;        // 參數bonus指定給這個物件的bonus
    }
    ...
}

重載 中看到過這個程式片段:

public class Some {
    private int a = 10;
    private String text = "n.a.";
    public Some(int a) {
        if(a > 0) {
            this.a = a;
        }

    }
    public Some(int a, String text) {
        if(a > 0) {
            this.a = a;
        }

        if(text != null) {
            this.text = text;
        }
    }
    ...
}

建構式的部份你發現了什麼?粗體字部份流程是重複的,重複在程式設計中是個不好的味道(Bad smell),你可以在建構式中呼叫另一個已定義的建構式。例如:

public class Some {
    private int a = 10;
    private String text = "n.a.";
    public Some(int a) {
        if(a > 0) {
            this.a = a;
        }
    }
    public Some(int a, String text) {
       this(a);
        if(text != null) {
            this.text = text;
        }
    }
    ...
}

在Java中,this()代表了呼叫另一個建構式,至於呼叫哪個建構式,則看呼叫this()時給的引數型態與個數而定,在上例中,this(a)會呼叫public Some(int a)版本的建構式,再執行if(text != null)之後的程式碼。this()呼叫只能出現在建構式的第一行。

在建構物件之後、呼叫建構式之前,若有想執行的流程,可以使用{}定義,直接來看個範例比較清楚:

package cc.openhome;

class Other {
    { System.out.println("物件初始區塊"); }
    
    Other() {
        System.out.println("Other() 建構式");
    }
    
    Other(int o) {
        this();
        System.out.println("Other(int o) 建構式");
    }
}

public class ObjectInitialBlock {
    public static void main(String[] args) {
        new Other(1);
    }
}

在這個範例中,呼叫了Other(int o)版本的建構式,而其中使用this()呼叫了Other()版本的建構式,如果有撰寫物件初始區塊,物件建立之後會先執行物件初始區塊,接著才呼叫你指定的建構式,所以結果就是:

物件初始區塊
Other() 建構式
Other(int o) 建構式

變數 介紹過final關鍵字,如果區域變數宣告了final,表示設值後就不能再變動,物件資料成員上也可以宣告final,如果是以下程式片段:

class Something {
    final int x = 10;
    ...
}

同樣地,程式中其它地方不能再有對x設值的動作,否則會編譯錯誤。那以下的程式片段呢?

public class Something {
    final int x;
    ...
}

x設為預設初始值0,而其它地方不能對再x設值?不對!如果物件資料成員被宣告為final,但沒有明確使用=指定值,那表示延遲物件成員值的指定,在建構式執行流程中,一定要有對該資料成員指定值的動作,否則編譯錯誤。

x有可能沒有初始值的編譯錯誤


在上圖中,雖然Something(int x)版本的建構式有對final物件成員x設值,但如果使用者呼叫了Something()版本的建構式,那x就不會被設值,因而編譯錯誤。如果你改為以下就可以通過編譯:

class Something {
    final int x;
    Something() {
        this(10);
    }
    Something(int x) {
        this.x = x;
    }
}