Java面試題之——類載入機制
阿新 • • 發佈:2018-12-30
Java面試題之——類載入機制
文章開始把我喜歡的這句話送個大家:這個世界上還有什麼比自己寫的程式碼執行在一億人的電腦上更酷的事情嗎,如果有那就是讓這個數字再擴大十倍。
分析一個類的初始化及執行順序大概可以按照如下步驟:
1.確定類變數的初始值。
在類載入的準備階段,JVM 會為類變數初始化零值,這時候類變數會有一個初始的零值。如果是被 final 修飾的類變數,則直接會被初始成使用者想要的值。2.初始化入口方法。
當進入類載入的初始化階段後,JVM 會尋找整個 main 方法入口,從而初始化 main 方法所在的整個類。當需要對一個類進行初始化時,會首先初始化類構造器(),之後初始化物件構造器()。
3.初始化類構造器。
JVM 會按順序收集類變數的賦值語句、靜態程式碼塊,最終組成類構造器由 JVM 執行。
4.初始化物件構造器。
JVM 會按照收整合員變數的賦值語句、普通程式碼塊,最後收集構造方法,將它們組成物件構造器,最終由 JVM 執行。
注意:
如果在初始化 main 方法所在類的時候遇到了其他類的初始化,那麼就先載入對應的類,載入完成之後返回。如此反覆迴圈,最終返回 main 方法所在類。
下面先看一個簡單的例子:
class Grandpa{
static
{
System.out.println("爺爺在靜態程式碼塊");
}
public Grandpa() {
System.out.println("我是爺爺~");
}
}
class Father extends Grandpa
{
static
{
System.out.println("爸爸在靜態程式碼塊");
}
public Father()
{
System.out.println("我是爸爸~");
}
}
class Son extends Father
{
static
{
System.out.println("兒子在靜態程式碼塊");
}
public Son()
{
System.out.println("我是兒子~");
}
}
public class InitializationDemo
{
public static void main(String[] args)
{
new Son(); //入口
}
}
輸出結果是:
爺爺在靜態程式碼塊
爸爸在靜態程式碼塊
兒子在靜態程式碼塊
我是爺爺~
我是爸爸~
我是兒子~
再來看一個複雜一點的例子:
public class Book {public static void main(String[] args)
{
staticFunction();
}
static Book book = new Book();
static
{
System.out.println("書的靜態程式碼塊");
}
{
System.out.println("書的普通程式碼塊");
}
Book()
{
System.out.println("書的構造方法");
System.out.println("price=" + price +",amount=" + amount);
}
public static void staticFunction(){
System.out.println("書的靜態方法");
}
int price = 110;
static int amount = 112;
}
他的輸出結果為:
書的普通程式碼塊書的構造方法
price=110,amount=0
書的靜態程式碼塊
書的靜態方法
執行過程:
當 JVM 在準備階段的時候,便會為類變數分配記憶體和進行初始化。此時,我們的 book 例項變數被初始化為 null,amount 變數被初始化為 0。當進入初始化階段後,因為 Book 方法是程式的入口,使用者指定一個要執行的主類(包含main()方法的那個類),虛擬機器會先初始化這個主類)。所以JVM 會初始化 Book 類,即執行類構造器 。
JVM 對 Book 類進行初始化首先是執行類構造器(按順序收集類中所有靜態程式碼塊和類變數賦值語句就組成了類構造器 ),後執行物件的構造器(按順序收整合員變數賦值和普通程式碼塊,最後收集物件構造器,最終組成物件構造器 )。
對於 Book 類,其類構造方法()可以簡單表示如下:
static Book book = new Book();
static
{
System.out.println("書的靜態程式碼塊");
}
static int amount = 112;
於是首先執行static Book book = new Book();這一條語句,這條語句又觸發了類的例項化。於是 JVM 執行物件構造器 ,收集後的物件構造器 程式碼:
{
System.out.println("書的普通程式碼塊");
}
int price = 110;
Book()
{
System.out.println("書的構造方法");
System.out.println("price=" + price +", amount=" + amount);
}
於是此時 price 賦予 110 的值,輸出:「書的普通程式碼塊」、「書的構造方法」。而此時 price 為 110 的值,而 amount 的賦值語句並未執行,所以只有在準備階段賦予的零值,所以之後輸出「price=110,amount=0」。
當類例項化完成之後,JVM 繼續進行類構造器的初始化:
static Book book = new Book();
static
{
System.out.println("書的靜態程式碼塊");
}
static int amount = 112;
即輸出:「書的靜態程式碼塊」,之後對 amount 賦予 112 的值。
到這裡,類的初始化已經完成,JVM 執行 main 方法的內容。
public static void main(String[] args)
{
staticFunction();
}
即輸出:「書的靜態方法」。
加油吧,程式設計師!