執行Java,執行java檔案
(6)Java.c中的LoadMainClass
位置jdk/src/share/bin/java.c
該方法負責載入main函數所在的類。該方法首先載入sun.launcher.LauncherHelper類,然後調用該類的checkAndLoadMain去找到main函數所在的類,相關代碼如下。
jclass cls = GetLauncherHelperClass(env);//這個函數載入了sun.launcher.LauncherHelper類 NULL_CHECK0(cls); if (JLI_IsTraceLauncher()) { start = CounterGet(); } NULL_CHECK0(mid = (*env)->GetStaticMethodID(env, cls,//找到方法id "checkAndLoadMain", "(ZILjava/lang/String;)Ljava/lang/Class;")); str = NewPlatformString(env, name); result = (*env)->CallStaticObjectMethod(env, cls, mid, USE_STDERR, mode, str);//調用這個靜態方法
(7)LauncherHelper.java中的checkAndLoadMain
位置:jdk/src/share/bin/classes/sun/launcher/LauncherHelper.java
Java代碼比較直觀,我就直接寫注釋了
</pre><p><pre name="code" class="java"> public static Class<?> checkAndLoadMain(boolean printToStderr, int mode, String what) { initOutput(printToStderr); // mode決定是直接傳入的主類還是jar檔案,即區分java -jar xxx.jar 還是 java xxx.class String cn = null; switch (mode) { case LM_CLASS: cn = what; break; case LM_JAR: cn = getMainClassFromJar(what);//這個函數的原理是抽取jar中的mainfest檔案得到其主類 break; default: // should never happen throw new InternalError("" + mode + ": Unknown launch mode"); } cn = cn.replace('/', '.'); Class<?> mainClass = null; try { mainClass = scloader.loadClass(cn);//使用scloader載入,如何載入水比較深,這裡就不展開說了。 } catch (NoClassDefFoundError | ClassNotFoundException cnfe) { if (System.getProperty("os.name", "").contains("OS X") && Normalizer.isNormalized(cn, Normalizer.Form.NFD)) { try { // On Mac OS X since all names with diacretic symbols are given as decomposed it // is possible that main class name comes incorrectly from the command line // and we have to re-compose it mainClass = scloader.loadClass(Normalizer.normalize(cn, Normalizer.Form.NFC)); } catch (NoClassDefFoundError | ClassNotFoundException cnfe1) { abort(cnfe, "java.launcher.cls.error1", cn); } } else { abort(cnfe, "java.launcher.cls.error1", cn); } } // set to mainClass appClass = mainClass; /* * Check if FXHelper can launch it using the FX launcher. In an FX app, * the main class may or may not have a main method, so do this before * validating the main class. */ if (mainClass.equals(FXHelper.class) || FXHelper.doesExtendFXApplication(mainClass)) { // Will abort() if there are problems with the FX runtime FXHelper.setFXLaunchParameters(what, mode); return FXHelper.class; } validateMainClass(mainClass);//這裡對主類有效性就行了驗證,代碼附在後面。 return mainClass; }
接下來給出了驗證主類是否有效代碼。
static void validateMainClass(Class<?> mainClass) { Method mainMethod; try { mainMethod = mainClass.getMethod("main", String[].class);//看看是否存在如下籤名的方法 main(String[] argvs) } catch (NoSuchMethodException nsme) { // invalid main or not FX application, abort with an error abort(null, "java.launcher.cls.error4", mainClass.getName(), FXHelper.JAVAFX_APPLICATION_CLASS_NAME); return; // Avoid compiler issues } int mod = mainMethod.getModifiers();//取得限定符 if (!Modifier.isStatic(mod)) {//如果不是static的則報錯 abort(null, "java.launcher.cls.error2", "static", mainMethod.getDeclaringClass().getName()); } if (mainMethod.getReturnType() != java.lang.Void.TYPE) { abort(null, "java.launcher.cls.error3",//如果不是void的也報錯 mainMethod.getDeclaringClass().getName()); } }
二、總結
這兩篇部落客要分析了執行java命令具體會發生一些什麼事情,通過閱讀代碼可以瞭解到配置的環境變數如何起作用,jvm何時初始化,以及主類載入及驗證過程。
本片部落格起碼還有以下幾點沒有深入的分析到:
jvm如何初始化。
env結構和vm結構的關係及實現。
scloader怎麼作用。
LauncherHelper如何載入。
這些問題或許會在後面的部落格進行分析。
java檔案是怎執行的
首先:使用javac命令把.java檔案編譯成.class檔案(位元組碼檔案)
然後:JVM(java虛擬機器)裝載.class檔案並翻譯成機器碼後運行java程式;
共同學習-----請參考:
我們手工執行java程式是這樣的:
1 在記事本中或者是UE的文字編輯器中,寫好來源程式;
2 使用javac命令把來源程式編譯成.class檔案;
編譯後的.class(類位元組碼)檔案中會包含以下內容:
ConstantPool:符號表;
FieldInfo:類中的成員變數資訊;
MethodInfo:類中的方法描述;
Attribute:可選的附加節點。
FieldInfo節點包含成員變數的名稱,諸如public,private,static等的標誌。ConstantValue屬性用來儲存靜態不變的成員變數的值。Deprecated和Synthetic被用來標記一個成員變數是不被推薦的或由編譯器產生的。
3 有了.class檔案,我們執行 java 解釋命令就可以運行java程式了。
現在我們主要討論一下,當執行 java這個命令後,會發生什麼事情呢?
首先,JVM裝載.class,也就是類裝載器裝載類位元組碼。一個類裝載器本身也是一個java類,所以,類裝載器自身也需要被另外一個類裝載器裝載,這就出現了類似先有蛋,還是先有雞的問題。但JAVA中的類裝載器的這個問題卻很容易解決。JAVA的虛擬機器(JVM)中內嵌了一個稱為Bootstrap類裝載器,它是用特定於作業系統的本地代碼實現的,屬於JAVA虛擬機器的核心,Bootstrap類不用專門的類裝載器去進行裝載。Bootstrap類負責載入JAVA核心包中的類(即rt.jar檔案中的類),這些類的Class.getClassLoader()方法傳回值為null,即表示是Bootstrap類裝載器。JAVA核心包中有另外兩個類裝載器:ExtClassLoader和AppClassLoader,它們都是用JAVA語言編寫的JAVA類,其中ExtClassLoader類裝載負責載入存放在<JAVA_HOME>/jre/lib/ext目錄下的jar包中的類,AppClassLoader負責載入應用程式的啟動執行類,即當使用java命令去啟動執行一個類時,JAVA虛擬機器使用AppClassLoader載入這個類。在編譯和運行JAVA程式時,都會通過ExtClassLoader類裝載器去<JAVA_HOME>/jre/lib/ext目錄下的JAR包中搜尋要載入的類,所以,如果將包含例如Servlet API的jar包或者是javamail.jar包複製到該目錄下,在編譯Servlet或JavaMail程式時,就不必在CLASSPATH環境變數中增加包含Servlet API的jar包或者是javamail.jar包檔案。
以上,就是一個JAVA程式執行的大致過程。
java不可以運行
開啟Java控制台--->安全
點開編輯網站列表
把你瀏覽的網站貼進去
確定,OK