1. 程式人生 > >java中class.forName和classLoader載入類的區分

java中class.forName和classLoader載入類的區分

   java中class.forName和classLoader都可用來對類進行載入。前者除了將類的.class檔案載入到jvm中之外,還會對類進行解釋,執行類中的static塊。而classLoader只幹一件事情,就是將.class檔案載入到jvm中,不會執行static中的內容,只有在newInstance才會去執行static塊。Class.forName(name, initialize, loader)帶參函式也可控制是否載入static塊。並且只有呼叫了newInstance()方法採用呼叫建構函式,建立類的物件 
事例程式碼如下: 
1.使用classLoader載入 

    System.out.println("before loadClass... "); 

    Class c =Test.class.getClassLoader().loadClass("com.hundsun.test.ClassInfo"); 
    System.out.println("after loadClass... "); 
    System.out.println("before newInstance... "); 
    ClassInfo info1 =(ClassInfo) c.newInstance(); 
    System.out.println("after newInstance... "); 

輸出結果: 
before loadClass... 

after loadClass... 
before newInstance... 
static invoked... 
contruct invoked... 
after newInstance... 

2.使用class.forName進行載入 

System.out.println("before class.forName"); 
Class cc =Class.forName("com.hundsun.test.ClassInfo"); 
System.out.println("after class.forName"); 
ClassInfo info2 =(ClassInfo) cc.newInstance(); 

輸出結果: 
before class.forName 
static invoked... 
after class.forName 
before newInstance... 
contruct invoked... 
after newInstance... 

下面說一下兩者具體的執行過程 
LoadClass()方法載入類及初始化過程: 
類載入(loadclass())(載入)——》newInstance()(連結+初始化) 
newInstance(): 
(開始連線)靜態程式碼塊——》普通變數分配準備(a=0;b=0;c=null)——》(開始初始化)普通變數賦值(a=1;b=2;c=”haha”)——》構造方法——》初始化成功。 


Class.forName(Stirng className)一個引數方法載入類及初始化過程: 
類載入(Class.forName())(載入)——》靜態程式碼塊——》newInstance()(連結+初始化) 

newInstance(): 
(開始連線)普通變數分配準備(a=0;b=0;c=null)——》(開始初始化)普通變數賦值(a=1;b=2;c=”haha”)——》構造方法——》初始化成功。 


Class.forName()三個引數的載入類及初始化過程同classLoader一樣。 

從上邊的斷點除錯可以看出,靜態程式碼塊不是在初始化階段完成的,它陷於類初始化,先於普通變數預設分配(整型分配為0,字串分配為null),這也就是為什麼我們不能在靜態程式碼塊中引用普通變數的原因之一,這與上面所謂的“分配”、“初始化”相違背。 

所以我覺得JVM的類載入及初始化過程應該是這樣的。 

1. 類載入:Bootstrap Loader——》Extended Loader——》System Loader 
2. 靜態程式碼塊初始化 
3. 連結: 
a) 驗證:是否符合java規範 
b) 準備:預設初始值 
c) 解析:符號引用轉為直接引用,解析地址 
4. 初始化 
a) 賦值:java程式碼中的初始值 
b) 構造:建構函式