參考博文:http://www.ibm.com/developerworks/cn/java/j-lo-clobj-init/java
上圖展現的是類生命週期流向;在本文裏,我只打算談談類的"初始化"以及"對象實例化"兩個階段。安全
類"初始化"階段,它是一個類或接口被首次使用的前階段中的最後一項工做,本階段負責爲類變量賦予正確的初始值。數據結構
Java 編譯器把全部的類變量初始化語句和類型的靜態初始化器統統收集到 <clinit> 方法內,該方法只能被 Jvm 調用,專門承擔初始化工做。ui
除接口之外,初始化一個類以前必須保證其直接超類已被初始化,而且該初始化過程是由 Jvm 保證線程安全的。另外,並不是全部的類都會擁有一個 <clinit>() 方法,在如下條件中該類不會擁有 <clinit>() 方法:this
該類既沒有聲明任何類變量,也沒有靜態初始化語句;spa
該類聲明瞭類變量,但沒有明確使用類變量初始化語句或靜態初始化語句初始化;.net
該類僅包含靜態 final 變量的類變量初始化語句,而且類變量初始化語句是編譯時常量表達式。線程
參考博文:http://blog.csdn.net/jbuilder3/article/details/5549104code
(1)經過java命令運行一個Java程序時,啓動一個Java虛擬機進程;orm
(2)Java虛擬機進程從啓動到終止的過程,稱爲Java虛擬機生命週期;
(3)程序生命週期和Java虛擬機生命週期是一致的,由於Java虛擬機進程從建立起的任務就是執行Java程序。
基礎說明:
public class Test { public Test(String name) { super(); this.name = name; } private String name; public static void main(String[] args) { Test test=new Test("1223344yuuuw"); System.out.println(test.name); new Person().eat(new Apple()); } }
a.Java程序要使用某個類時,Java虛擬機要確保這個類被加載,鏈接和運行,其中鏈接包括驗證,準備和解析。
b.加載:查找並加載類的二進制數據;
c.鏈接
c.1 驗證:確保加載類的正確性;
c.2 準備:爲靜態變量分配內存,並將其初始化爲默認值;
c.3 解析:將類中的符號引用轉換爲直接引用。
d初始化:
給類的靜態變量賦予正確的初始值
(1)加載(加載的最終目標是實現將編譯後的class文件(class文件採用字節碼,是JVM的機器語言)裝入內存運行時數據區的方法區中,並在內存運行時數據區的堆區生成一個class對象,這個對象能夠引用到方法區中的類定義)
1.1 加載須要完成:
1.1.1 將類的.class文件中的二進制數據讀到內存中的運行時數據區的方法區;
1.1.2 在堆區建立一個java.lang.Class對象(對象都放在堆區),用於封裝類在方法區內的數據結構。
1.2 加載的最終產品是位於運行時數據區堆區的java.lang.Class對象,Class對象封裝了類在方法區的數據結構,並向Java程序提供訪問類在方法區內的數據結構的接口
1.3 類的加載由加載器完成
1.3.1 Java虛擬機自帶的加載器(若是Java虛擬機是一個C++程序,則這些加載器是這個C++程序的一部分)
包括啓動類加載器,擴展類加載器和系統類加載器《後兩個都是java.lang.Class類的實例》
1.3.2 用戶自定義的類加載器
java.lang.Class的子類的實例,用戶能夠經過它定製類的加載方式(用戶自定義的類加載器使Java具備動態鏈接的特性,即Java無需在編譯時肯定須要的組件<類>,在運行時動態肯定須要加載的類)
類加載器在預料某個類將要被使用時就預先加載它,若是在預先加載過程當中遇到.class文件缺失,類加載器等到程序首次調用類的時候報錯
Java中的類加載器採用父親委託機制,使用加載器加載類是,首先看其父親是否可以完成類的加載,若是能夠,則由父親完成類的加載,返回加載的類的java.lang.Class對象,注意,加載器之間的父子關係並非java中普通的繼承關係,而是一種包含關係,具備父子關係的類也許是不一樣的類型。
(2)鏈接
在鏈接階段對靜態變量分配內存(靜態變量是類做用域變量,僅在類加載時分配一次內存),並賦予默認值。
(3)初始化
說了這麼多,類的初始化時機就是在"在首次主動使用時",那麼,哪些情形下才符合首次主動使用的要求呢?
首次主動使用的情形:
建立某個類的新實例時--new、反射、克隆或反序列化;
調用某個類的靜態方法時;
使用某個類或接口的靜態字段或對該字段賦值時(final字段除外);
調用Java的某些反射方法時
初始化某個類的子類時
在虛擬機啓動時某個含有main()方法的那個啓動類。
除了以上幾種情形之外,全部其它使用JAVA類型的方式都是被動使用的,他們不會致使類的初始化。
類的初始化過程是執行類的初始化語句,包括靜態變量的聲明語句,以及靜態代碼塊,靜態代碼塊的做用便是爲靜態變量賦初始化值。