在Java中,想必所有人都不會對main方法感到陌生,main方法是Java應用程式的入口方法。程序運行時,要執行的第一個方法就是main方法。
在使用Java寫下第一個hello world的時候,我們需要創建一個main方法,當我們使用Spring Boot啟動一個web應用的時候,我們也同樣需要一個main方法。
當我們在Intellij IDEA中想要創建main 方法的時候,只需要輸入psvm就會自動幫忙創建一個main方法:
我們得到一個main方法後,不知道你有沒有發現,任何時候,我們要創建的main方法的形式都是一樣的:
public static void main(String[] args) {
}
首先都是public的、都是static的,返回值都是void,方法名都是main,入參都是一個字符串數組。
以上的方法聲明中,唯一可以改變的的部分就是方法的參數名,你可以把args改成任意你想要使用的名字。
當然,main方法還可以寫成以下形式,不過其實沒啥區別:
public static void main(String... args) {
}
那麼,不知道大家有沒有想過,為什麼main方法必須得是public static void類型的,他的參數又必須得是一個字符串數組呢?
在《Java語言規範》中,對於Java虛擬機的啟動給出了明確的定義:Java虛擬機是通過加載指定的類,然後調用該類中的main方法而啟動的。
也就是說,通過調用某個指定類的main方法,傳遞給他單個的字符串數組參數,就可以啟動Java虛擬機。
一個main方法想要被執行,需要經過幾個步驟,首先對應的類需要被虛擬機加載,然後需要進行連結和初始化、之後才是調用main方法。
那麼一個方法想要被調用,根據他的訪問限定符以及方法類型不同,被調用的條件也是不同的。
Java中,可以使用訪問控制符來保護對類、變量、方法和構造方法的訪問。Java 支持 4 種不同的訪問權限。
default (即默認,什麼也不寫): 在同一包內可見,不使用任何修飾符。使用對象:類、接口、變量、方法。
private : 在同一類內可見。使用對象:變量、方法。注意:不能修飾類(外部類)
public : 對所有類可見。使用對象:類、接口、變量、方法
protected : 對同一包內的類和所有子類可見。使用對象:變量、方法。注意:不能修飾類(外部類)。
以上四種控制符都可以用來修飾方法,但是被修飾的方法的訪問權限就不同了。
而對於main方法來說,我們需要通過JVM直接調用他,那麼就需要他的限定符必須是public的,否則是無法訪問的。
static是靜態修飾符,被他修飾的方法我們稱之為靜態方法,靜態方法有一個特點,那就是靜態方法獨立於該類的任何對象,它不依賴類特定的實例,被類的所有實例共享。只要這個類被加載,Java虛擬機就能根據類名在運行時數據區的方法區內定找到他們。
而對於main方法來說,他的調用過程是經歷了類加載、連結和初始化的。但是並沒有被實例化過,這時候如果想要調用一個類中的方法。那麼這個方法必須是靜態方法,否則是無法調用的。
如果大家對於C語言和C++語言有一定的了解的話,就會知道,像 C、C++ 這種以 int 為 main 函數返回值的程式語言。
這個返回值在是程序退出時的 exit code,一般被命令解釋器或其他外部程序調用已確定流程是否完成。一本正常情況下用 0 返回,非 0 為異常退出。
而在Java中,這個退出過程是由JVM進行控制的,在發生以下兩種情況時,程序會終止其所有行為並退出:
1、所有不是後臺守護線程的線程全部終止。
2、某個線程調用了Runtime類或者System類的exit方法,並且安全管理器並不禁止exit操作。
上面的兩種情況中,第二種情況一旦發生,JVM是不會管main方法有沒有執行完的,他都會終止所有行為並退出,這時候main方法的返回值是沒有任何意義的。
所以,main方法的返回值就被固定要求為void。
為什麼 main 方法的入參是字符串數組(String[])Java應用程式是可以通過命令行接受參數傳入的,從命令行傳遞的參數可以在java程序中接收,並且可以用作輸入。
因為命令行參數最終都是以字符串的形式傳遞的,並且有的時候命令行參數不止一個,所以就可能傳遞多個參數。
這時候,作為Java應用程式執行的入口,main方法就需要能夠接受這多個字符串參數,那麼就使用字符串數組了。
main方法是JVM執行的入口,為了方便JVM調用,所以需要將他的訪問權限設置為public,並且靜態方法可以方便JVM直接調用,無需實例化對象。
因為JVM的退出其實是不完全依賴main方法的,所以JVM並不會接收main方法的返回值,所以給main方法定義一個返回值沒有任何意義。所以main方法的返回值為void。
為了方便main函數可以接受多個字符串參數作為入參,所以他的形參類型被定義為String[]。