知識:
我們都知道程序都是運行在JVM上的,而且,JVM的加載機制是RTTI(Run-Time Type Identification,通過運行時類型識別),那麼JVM是怎麼加載類以及生成加載對象的呢。
當我們編寫並且編譯了一個新類,就會產生一個Class對象,這個對象用來創建所有的“常規對象”,例如我們新NEW的對象。這時,這個類是沒有加載到JVM中的。
第一次使用類時,纔將類加載到JVM中,使用到了JVM的類加載器。
程序使用類的時候,JVM的類加載器會去檢查這個類的Class對象是否已經被加載,如果尚未加載就會去.class文件中加載。如果已經加載,就不需要再加載一次了。
初始化順序如下:
- 靜態初始化:只在類加載的時候初始化一次。之後不管生成多少類的對象都不再初始化。
- 成員變量:類在生成對象的時候,必須先初始化類的成員變量。所以,在調用類的構造方法之前,類的成員變量已經被初始化。
- 非靜態代碼塊{···}:也是在調用類的構造方法之前執行。
- 成員變量和非靜態代碼塊的初始化順序,按照代碼出現的順序初始化。
- 構造方法
好了,看程序:
class Candy{
static int i=0;
print p=new print();
{
i=1;
System.out.println("Loading candy not static");
}
static{
i=2;
System.out.println("Loading candy static");
}
public Candy(){
System.out.println("Loading candy()");
System.out.println("i="+i);
}
}
class print{
print(){
System.out.println("print !!!!!!!");
}
}
public class ObjectClass {
public static void main(String args[]){
new Candy();
System.out.println("~~~~~~~~~~~~~~~~~~~~~~1");
new Candy();
System.out.println("~~~~~~~~~~~~~~~~~~~~~~2");
}
}
輸出如下:
Loading candy static
print !!!!!!!
Loading candy not static
Loading candy()
i=1
~~~~~~~~~~~~~~~~~~~~~~1
print !!!!!!!
Loading candy not static
Loading candy()
i=1
~~~~~~~~~~~~~~~~~~~~~~2
注:static子句是類加載時執行的語句
所以可以看到,Loading candy static這句輸出只被打印了一次。證明,JVM只加載類一次。
其次,我們可以看出,static子句,成員變量,構造塊(用{}括起來的程序),構造方法的加載順序依次是:
static子句首先被加載,但是隻加載一次。其次是成員變量,構造塊,(這裏需要說明的是,如果成員變量和構造塊互換位置,那麼輸出時語句也將互換)
最後是構造方法。
Class.forName()
這裏我們引入一個比較特別的用法Class.forName().他的作用是,在JVM中,如果類還未加載就去加載他,返回的是一個Class對象的引用。
public static void main(String args[]){
//new Candy();
try{
Class.forName("leet.Candy");
}catch(ClassNotFoundException e){
System.out.println("could not found candy");
}
System.out.println("~~~~~~~~~~~~~~~~~~~~~~1");
new Candy();
System.out.println("~~~~~~~~~~~~~~~~~~~~~~2");
try{
Class.forName("leet.Candy");
}catch(ClassNotFoundException e){
System.out.println("could not found candy");
}
System.out.println("~~~~~~~~~~~~~~~~~~~~~~3");
}
輸出:
Loading candy static
~~~~~~~~~~~~~~~~~~~~~~1
Loading candy not static
Loading candy()
i=1
~~~~~~~~~~~~~~~~~~~~~~2
~~~~~~~~~~~~~~~~~~~~~~3
Class.forName()返回的是類的引用,如果JVM中沒有加載這個類,就會去加載。如果只是生成一個對象的引用,我們可以發現,其實JVM什麼也沒幹。
public class ObjectClass {
public static void main(String args[]){
Candy c;
}
}
這樣的話,什麼都不會輸出。