From Gossip@Openhome

Java Gossip: 建構方法(Constructor)

在定義類別時,您可以使用「建構方法」(Constructor)來進行物件的初始化,而在Java中並沒有 「解構方法」(Destructor),而是利用finalize()函式來達到解構方法的作用,這則在 垃圾回收 討論。

在Java中建構方法是與類別名稱相同的方法成員,且沒有傳回值,例如:
public class SafeArray {
    // ..
 
    public SafeArray() {  // 建構方法
        // ....
    }
 
    public SafeArray(參數) {  //
        // ....
    }
}

在建構方法中,您可以定義無參數的建構方法,或具有參數的建構方法,程式在運行時,會根據配置物件時所指定的引數資料型態等來決定,該使用哪一個建構方法。

下面這個程式中,您實作「安全的陣列」,使用我們所定義的陣列類別可以動態配置陣列長度,並可事先檢查存取陣列的索引是否超出陣列長度,在這個陣列類別中,您實作了幾個簡單的功能,像是傳回陣列長度、設定陣列元素值、取得陣列元素值等等,我們的類別定義如下:

  • SafeArray.java
public class SafeArray { 
private int[] arr;

public SafeArray() {
this(10);
}

public SafeArray(int length) {
arr = new int[length];
}

public int[] getArray() {
return arr;
}

public int getElement(int i) {
if(i >= arr.length || i < 0) {
System.err.println("索引錯誤");
return 0;
}

return arr[i];
}

public int getLength() {
return arr.length;
}

public void setElement(int i, int data) {
if(i >= arr.length || i < 0) {
System.err.println("索引錯誤");
return;
}

arr[i] = data;
}
}

建構方法中,如果不指定引數的話,就會預設配置10個元素的陣列,您也可以由指定的長度來配置陣列;您在無引數的建構方法中直接使用this() 來呼叫另一個有參數的建構方法,這是一種經常的作法,可以避免撰寫一些重覆的原始碼。

下面這個程式示範如何使用自訂的安全陣列類別:

  • UseConstructor.java
 
public class UseConstructor {
public static void main(String[] args) {
// 預設10個元素
SafeArray arr1 = new SafeArray();
// 指定配置20個元素
SafeArray arr2 = new SafeArray(20);

for(int i = 0; i < arr1.getLength(); i++)
arr1.setElement(i, (i+1)*10);

for(int i = 0; i < arr2.getLength(); i++)
arr2.setElement(i, (i+1)*10);

for(int element : arr1.getArray())
System.out.print(element + " ");
System.out.println();

for(int element : arr2.getArray())
System.out.print(element + " ");
System.out.println();
}
}


上面的程式中,您配置了兩個SafeArray物件,一個使用預設的建構方法,所以arr1的陣列元素會有10個,一個使用指定長度的建構方法,所以arr2的陣列元素個 數是我們指定的20,建構方法依引數不同而自行決定該使用哪一個建構方法。

物件在建構之前,物件的屬性必須先初始完畢才會執行建構式,例如:
public class Some {
    private Other other = new Other();

    public Some() {
         System.out.println("Some");
    }
}

public class Other {
    public Other() {
        System.out.println("Other");
    }
}

如果建構Some:
Some some = new Some();

由於先初始Some的屬性成員,所以會先顯示"Other",再顯示"Some"。

如果您如下撰寫:
public class Test {
    {
        System.out.println("initial...");
    }

    public Test() {
        System.out.println("Test");
    }

    public Test(int i) {
        System.out.println("Test i");
    }

    public static void main(String[] args) {
        new Test();
        new Test(1);
    }
}

在 { 與 } 之間的程式,會於執行時期自動加入物件建構流程的開頭(而不是編譯時期展開程式碼),也就是先執行{與}間的程式,再執行指定的建構方法,所以程式將顯示:

initial...
Test
initial...
Test i