Constructor 和 Static Initializer 的差別
前言:
泰勞因為接觸Android才開始學習用Java寫程式,有很多基本觀念並沒有在一開始就建立起來,因此開發過程中總是曲折離奇,時常耗費過多的時間來處理語法或是愚蠢的錯誤。雖然說「做中學」並沒有不好,而「錯中學」對工程師而言本來就是該有的態度,但若是能有扎實的基本觀念來支撐,一定能讓專案開發的更順利更完美!
建構子(Constructor):
在Java裡有個特殊的方法叫做建構子,Construct這個動詞本身就有建造、建構的意思,動詞後面加上er或or變成名詞,則有「人」的意思,例如:teach是「教」,teacher是「教師」;pitch是「投」,pitcher是「投手」等等,對此有興趣的可以去翻閱高如峯著作的「神奇的字元素」。因此Constructor在這裡可解讀為建構某些東西的方法。
特性:
Constructors are special methods invoked when an object is created and are used to initialize them. A constructor name must be same as its class name.
建構子是當物件被建立(new)時,用於初始化物件屬性的方法。建構子的名稱必須和其類別名稱相同。
上面的範例定義了Program類別用於初始化物件的建構子,並在main方法裡建立一個Program物件,此時Program類別裡的建構子就會被執行,因此會輸出Constructor這個字串。那如果建立兩個Program物件呢?
根據定義,建構子在物件被建立時就會執行,因此上面這段程式建立了兩個Program物件,建構子就會執行兩次,所以最後會輸出兩次Constructor字串。
一個類別裡,可以擁有多個「不同參數」的建構子。上面的範例是沒有參數的版本,當然也可以定義需要參數的建構子,若要使用,就必須在建立物件的同時,將參數帶入,這樣Java才能判斷要用哪一個建構子來初始化物件。
上面範例程式輸出的結果如下圖所示,Java會依照不同的參數建構出不一樣的Program物件。
Static Initializer:
在Java裡有個功能與建構子非常相似,它就是「Static Initializer」,有時也會稱它為Class Initializer,因為它扮演的角色與類別可說是息息相關。Static Initializer必須使用Static關鍵字來修飾,而寫在Static區塊裡的程式,會習慣以Static Block來稱呼。
特性:
Static Initializer executed once at the time of class-loading and initialized by JVM. It can be thought of as a "Class Constructor".
Static Initializer的功能在於初始化類別,當類別初次被使用、被載入至JVM時,會執行寫在Static Block裡的程式碼。舉個例子,載入外部的函式庫,就是個常見的使用時機,如下範例所示。
定義中特別提到可以將Static Initializer視為Class Constructor,若直接翻譯成中文就是類別的建構子(此翻譯無文獻,大家參考就好)。對比文章開頭那個用於初始化物件的建構子,它們兩之間的功能非常類似,但目的卻不一樣喔!
接著來看一個範例,在類別裡定義Static Initializer與Constructor,並在main方法裡建立兩個物件,觀察看看到底會輸出什麼結果。
建議大家先想一想、動一動頭腦、泡一泡牛奶再看答案。
相信大家都答對了吧!只要把它們之間不同之處搞懂了,就不會覺得困難。後面還有一個有趣的範例,直接來看程式碼吧!
Program.java:
Test.java:
Test.java與Program.java置於同一個目錄底下,將程式編譯之後,分別執行兩個Java檔,會得到什麼結果呢?
有沒有發現Program與Test最關鍵的差別在哪裡呢?仔細思考就會理解,因為Program在自己的main方法裡建立Program物件時,Program類別的main方法已經被執行了,也就是說Program類別已經被JVM載入了。相較之下,Test在main方法裡建立Program物件時,Program類別才初次被使用,因此輸出字串的順序才會有些許不同。
泰勞因為接觸Android才開始學習用Java寫程式,有很多基本觀念並沒有在一開始就建立起來,因此開發過程中總是曲折離奇,時常耗費過多的時間來處理語法或是愚蠢的錯誤。雖然說「做中學」並沒有不好,而「錯中學」對工程師而言本來就是該有的態度,但若是能有扎實的基本觀念來支撐,一定能讓專案開發的更順利更完美!
建構子(Constructor):
在Java裡有個特殊的方法叫做建構子,Construct這個動詞本身就有建造、建構的意思,動詞後面加上er或or變成名詞,則有「人」的意思,例如:teach是「教」,teacher是「教師」;pitch是「投」,pitcher是「投手」等等,對此有興趣的可以去翻閱高如峯著作的「神奇的字元素」。因此Constructor在這裡可解讀為建構某些東西的方法。
特性:
Constructors are special methods invoked when an object is created and are used to initialize them. A constructor name must be same as its class name.
建構子是當物件被建立(new)時,用於初始化物件屬性的方法。建構子的名稱必須和其類別名稱相同。
public class Program
{
//建構子
Program(){
System.out.println("Constructor");
}
public static void main(String[] args) {
//建立Program物件,並取名為p1
Program p1 = new Program();
}
}
{
//建構子
Program(){
System.out.println("Constructor");
}
public static void main(String[] args) {
//建立Program物件,並取名為p1
Program p1 = new Program();
}
}
上面的範例定義了Program類別用於初始化物件的建構子,並在main方法裡建立一個Program物件,此時Program類別裡的建構子就會被執行,因此會輸出Constructor這個字串。那如果建立兩個Program物件呢?
public static void main(String[] args) {
Program p1 = new Program();
Program p2 = new Program();
}
Program p1 = new Program();
Program p2 = new Program();
}
根據定義,建構子在物件被建立時就會執行,因此上面這段程式建立了兩個Program物件,建構子就會執行兩次,所以最後會輸出兩次Constructor字串。

public class Program
{
//建構子
Program(){
System.out.println("Constructor");
}
Program(String name){
System.out.println("Name:"+name);
}
Program(int age){
System.out.println("Age:"+age);
}
public static void main(String[] args) {
Program p1 = new Program();
Program p2 = new Program("Kuanlin");
Program p3 = new Program(18);
}
}
{
//建構子
Program(){
System.out.println("Constructor");
}
Program(String name){
System.out.println("Name:"+name);
}
Program(int age){
System.out.println("Age:"+age);
}
public static void main(String[] args) {
Program p1 = new Program();
Program p2 = new Program("Kuanlin");
Program p3 = new Program(18);
}
}
上面範例程式輸出的結果如下圖所示,Java會依照不同的參數建構出不一樣的Program物件。

在Java裡有個功能與建構子非常相似,它就是「Static Initializer」,有時也會稱它為Class Initializer,因為它扮演的角色與類別可說是息息相關。Static Initializer必須使用Static關鍵字來修飾,而寫在Static區塊裡的程式,會習慣以Static Block來稱呼。
特性:
Static Initializer executed once at the time of class-loading and initialized by JVM. It can be thought of as a "Class Constructor".
Static Initializer的功能在於初始化類別,當類別初次被使用、被載入至JVM時,會執行寫在Static Block裡的程式碼。舉個例子,載入外部的函式庫,就是個常見的使用時機,如下範例所示。
public class Program
{
//Static Initializer
static{
System.loadLibrary("myLib");
}
......
}
{
//Static Initializer
static{
System.loadLibrary("myLib");
}
......
}
定義中特別提到可以將Static Initializer視為Class Constructor,若直接翻譯成中文就是類別的建構子(此翻譯無文獻,大家參考就好)。對比文章開頭那個用於初始化物件的建構子,它們兩之間的功能非常類似,但目的卻不一樣喔!
Static Initializer | VS. | Constructor |
靜態初始化區塊 | 中文翻譯 | 建構子 |
類別 | 初始化目標 | 物件 |
類別被載入至JVM | 初始化時機 | 物件被建立(new) |
需使用Static關鍵字來修飾 | 特殊要求 | 建構子名稱需與其類別名稱相同 |
接著來看一個範例,在類別裡定義Static Initializer與Constructor,並在main方法裡建立兩個物件,觀察看看到底會輸出什麼結果。
public class Program
{
static{
System.out.println("Static Block");
}
Program(){
System.out.println("Constructor");
}
public static void main(String[] args) {
Program p1 = new Program();
Program p2 = new Program();
}
}
{
static{
System.out.println("Static Block");
}
Program(){
System.out.println("Constructor");
}
public static void main(String[] args) {
Program p1 = new Program();
Program p2 = new Program();
}
}
建議大家先想一想、動一動頭腦、泡一泡牛奶再看答案。
相信大家都答對了吧!只要把它們之間不同之處搞懂了,就不會覺得困難。後面還有一個有趣的範例,直接來看程式碼吧!
Program.java:
public class Program
{
static{
System.out.println("Static Block");
}
Program(){
System.out.println("Constructor");
}
public static void main(String[] args) {
System.out.println("Program");
Program p1 = new Program();
Program p2 = new Program();
}
}
{
static{
System.out.println("Static Block");
}
Program(){
System.out.println("Constructor");
}
public static void main(String[] args) {
System.out.println("Program");
Program p1 = new Program();
Program p2 = new Program();
}
}
Test.java:
public class Test{
public static void main(String[] args){
System.out.println("Test");
Program p3 = new Program();
Program p4 = new Program();
}
}
public static void main(String[] args){
System.out.println("Test");
Program p3 = new Program();
Program p4 = new Program();
}
}
Test.java與Program.java置於同一個目錄底下,將程式編譯之後,分別執行兩個Java檔,會得到什麼結果呢?
$ javac Program.java
$ java Program
$ java Program
$ javac Test.java
$ java Test
$ java Test
有沒有發現Program與Test最關鍵的差別在哪裡呢?仔細思考就會理解,因為Program在自己的main方法裡建立Program物件時,Program類別的main方法已經被執行了,也就是說Program類別已經被JVM載入了。相較之下,Test在main方法裡建立Program物件時,Program類別才初次被使用,因此輸出字串的順序才會有些許不同。
留言
張貼留言