類加載順序 Class對象

知識:

我們都知道程序都是運行在JVM上的,而且,JVM的加載機制是RTTI(Run-Time Type Identification,通過運行時類型識別),那麼JVM是怎麼加載類以及生成加載對象的呢。

當我們編寫並且編譯了一個新類,就會產生一個Class對象,這個對象用來創建所有的“常規對象”,例如我們新NEW的對象。這時,這個類是沒有加載到JVM中的。

第一次使用類時,纔將類加載到JVM中,使用到了JVM的類加載器。

程序使用類的時候,JVM的類加載器會去檢查這個類的Class對象是否已經被加載,如果尚未加載就會去.class文件中加載。如果已經加載,就不需要再加載一次了。

初始化順序如下:

  1. 靜態初始化:只在類加載的時候初始化一次。之後不管生成多少類的對象都不再初始化。
  2. 成員變量:類在生成對象的時候,必須先初始化類的成員變量。所以,在調用類的構造方法之前,類的成員變量已經被初始化。
  3. 非靜態代碼塊{···}:也是在調用類的構造方法之前執行。
  4. 成員變量和非靜態代碼塊的初始化順序,按照代碼出現的順序初始化。
  5. 構造方法

好了,看程序:

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;

	}

}

這樣的話,什麼都不會輸出。

發佈了27 篇原創文章 · 獲贊 0 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章