天天看點

Java main如何被加載,Java的main方法與類的加載的聯系

如長期以來衆多人的看法:我想的東西很怪異。這種看法多少有些中肯成份,這次的東西怪異到我都不知道該為它起什麼标題了,但必須寫,就胡謅了一個。

問題源自我在測試題裡面作答的兩道習題,我先遇見老紫竹老師出的題目,大意是Java中是否一定要依賴main方法來執行程式代碼?我當時很認真地答了是,我認為程式一定要有入口,結果我錯了;但是,前天我又遇到了這樣的類似問題,這個問題是一位同學出的,由于我很在意那個錯誤是以在一道多選題中沒有将main方法勾選在内,于是,我又錯了,搞來搞去我就兩次都栽在了一個混沌的問題上,故此,不免要thinking in Java一下了。

在說明問題之前不免要鋪陳一番。

Java的類是用到才開始加載的,并且在每個類的構造器調用之前,類的每個域(成員變量)都要首先被編譯器初始化一次,然後才輪到構造器來幹活兒。但是,Java的初始化是惰性的,它沒有C++構造函數的苛刻的要求,Java編譯器會保證每個變量在使用之前會被初始化,是以Java中隻要求程式員在合适的地方為類成員給一個有效的值即可。

一個有益于問題突破的事實是,一個static變量在沒有類執行個體的時候也是可以使用的,這就要求static必須被恰當地初始化,也就是說,在構造器的調用之前,加載類的時候,Java編譯器會允許JVM運作一段代碼,至少可能會有幾行。

這裡就出現了一個有趣的問題:程式開始的時候類加載的時候所做的工作流程是怎樣的?

Thinking in Java告訴我,每當執行Java編譯器的時候,編譯器會尋找指定的類,當它找到類時,首先需要初始化static變量,因為這些成員可以在沒有執行個體的情況下運作,接着,再按照變量的聲明順序依次初始化類的成員,成員初始化完畢之後才為自己調用構造器,一切進行完畢之後,才可以調用方法。但主類比較特殊,主方法會在構造器之前,static變量初始化之後調用,這是由于Java的惰性初始化,在main方法被調用之前無法知道是否存在主類的執行個體。

Java的初始化和構造的分離使得Java提供了代碼塊作為初始化成員的工具和支援無名類的利器,而這樣一來,初始化的工作就不免會被擴充,程式員可以嵌入額外的初始化步驟。由于Java的成員分普通成員和static成員,初始化代碼塊也分static的,例如:

public class Foo{       int a;       int b;       static int c;      {             a=-1;             b=1;      }//這個就是所謂的初始化代碼塊      static {              c=100;      }//static成員有專屬的static初始化代碼塊      Foo(){Syetem.out.println("Foo creat now!")}//這個和C++确實不同,權限大為縮減 };      接下來就是問題的實質了:如何在沒有main方法的情況下執行程式段?把程式段寫在static塊裡面就可以了!當執行加載主類指令時,static塊中的代碼會在類對象初始化之前執行完畢。注意,這個隻是執行代碼段而已,并且隻能執行static初始化代碼塊内的代碼,并不是所謂的執行程式。首先一點,你這static代碼塊無法接受到傳遞過去的參數。而且,如果打算運作上面的類,肯定會失敗,因為在初始化完成之後JVM找不到入口,入口都沒有當然程式也就特别異常了。       問題的思考就到這裡,收工睡覺。