為什么說Java是跨平臺語言
Java語言的運行環(huán)境是在Java虛擬機中。 Java虛擬機消除了各個平臺之間的差異,只要操作系統(tǒng)平臺下安裝了Java虛擬機,那么使用Java開發(fā)的東西都能在其上面運行。如下圖所示:

Java虛擬機對各個平臺而言,實質上是一個可執(zhí)行程序。例如在windows平臺下,java虛擬機就是一個java.exe進程而已。
JVM虛擬機啟動和加載類過程
下面以一個簡單的java程序,分析虛擬機啟動過程。
public class HelloWorld {
public static void main(String[] args) {
System.out.println("hello world");
}
}
當我們運行上面程序時,將會啟動一個虛擬機進程,不管Java程序有多么復雜,啟動了多少線程,它們都將處于該Java虛擬機進程里。具體過程如下:
1、根據(jù)JVM的內存配置,為JVM申請?zhí)囟ù笮〉膬却婵臻g

2、創(chuàng)建一個引導類加載器實例
JVM申請好內存空間后,JVM會創(chuàng)建一個引導類加載器(Bootstrap Classloader)實例,引導類加載器是使用C++實現(xiàn)的,負責加載JVM虛擬機運行時所需的基本系統(tǒng)級別的類,如java.lang.String, java.lang.Object等。引導類加載器(Bootstrap Classloader)會讀取 {JRE_HOME}/lib 下的jar包和配置,然后將這些系統(tǒng)類加載到方法區(qū)內。
方法區(qū)用于存儲已經被虛擬機加載過的類信息、常量、靜態(tài)變量、即時編譯器編譯出的代碼等數(shù)據(jù)。

Class是一個實實在在的類,在包 java.lang 下。它跟我們自己定義的類一樣,是一個實實在在的類,Class對象就是這個Class類的實例了。在Java里,所有的類的根源都是Object類,Class也不例外,它是繼承自Object的一個特殊的類,它內部可以記錄類的成員、接口等信息。
3、創(chuàng)建JVM 啟動器實例 Launcher,并取得類加載器ClassLoader
上述步驟完成,JVM基本運行環(huán)境就準備就緒了。此時,JVM虛擬機會調用已經加載在方法區(qū)的類sun.misc.Launcher 的靜態(tài)方法getLauncher(), 獲取sun.misc.Launcher 實例:
sun.misc.Launcher launcher = sun.misc.Launcher.getLauncher(); //獲取Java啟動器
ClassLoader classLoader = launcher.getClassLoader(); //獲取類加載器ClassLoader用來加載class到內存來
sun.misc.Launcher 使用了單例模式設計,保證一個JVM虛擬機內只有一個sun.misc.Launcher實例。在Launcher的內部,其定義了兩個類加載器(ClassLoader),分別是sun.misc.Launcher.ExtClassLoader和sun.misc.Launcher.AppClassLoader,這兩個類加載器分別被稱為拓展類加載器(Extension ClassLoader) 和 應用類加載器(Application ClassLoader).如下圖所示:

此時的 launcher.getClassLoader() 方法將會返回 AppClassLoader實例。
當AppClassLoader加載類時,會首先嘗試讓父加載器ExtClassLoader進行加載,如果父加載器ExtClassLoader加載成功,則AppClassLoader直接返回父加載器ExtClassLoader加載的結果;
如果父加載器ExtClassLoader加載失敗,AppClassLoader則會判斷該類是否是引導的系統(tǒng)類(即是否是通過Bootstrap類加載器加載,這會調用Native方法進行查找);
若要加載的類不是系統(tǒng)引導類,那么ClassLoader將會嘗試自己加載,加載失敗將會拋出“ClassNotFoundException”。
上面討論的應用類加載器AppClassLoader的加載類的模式就是我們常說的雙親委派模型(parent-delegation model).
對于某個特定的類加載器而言,應該為其指定一個父類加載器,當用其進行加載類的時候:
- 委托父類加載器幫忙加載;
- 父類加載器加載不了,則查詢引導類加載器有沒有加載過該類;
- 如果引導類加載器沒有加載過該類,則當前的類加載器應該自己加載該類;
- 若加載成功,返回 對應的Class<T> 對象;若失敗,拋出異?!癈lassNotFoundException”。
4、使用類加載器ClassLoader加載HelloWorld類
通過 launcher.getClassLoader()方法返回AppClassLoader實例,接著就是AppClassLoader加載HelloWorld類的時候了。
5、加載完成時候JVM會執(zhí)行HelloWorld類的main方法入口
6、java程序運行結束,JVM銷毀
類的初始化
在Java類中對類變量指定初始值有兩種方式,一是聲明類變量時指定初始值;二是使用靜態(tài)初始化塊為類變量指定初始值。
JVM會按照這些語句在程序中的排列順序依次執(zhí)行它們。另外,如果類的父類還沒初始化,會先初始化父類。例如下面的類:
public class Test {
static {
b = 6;
System.out.println("---------");
}
static int a = 5;
static int b = 9;
static int c;
public static void main(String[] args) {
System.out.println(Test.b);//結果為9
}
}