記得在剛學(xué)JAVA的時(shí)候,類的加載機(jī)制和初始化順序經(jīng)常被弄的糊里糊涂,其實(shí)當(dāng)我們不太了解某些事情的時(shí)候,不防去做一做實(shí)驗(yàn),讓代碼的運(yùn)行結(jié)果說(shuō)話,這或許能幫助我們更好地了解一些事情.今天我們就用一些代碼來(lái)看一下類是如何被加載的,并且當(dāng)有繼承關(guān)系的時(shí)候,類的加載順序又是怎么樣的.
先看代碼吧
/*
* Test4.java
*
* Created on 2007-9-21, 9:33:31
*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package test1;
/**
*
* @author hadeslee
*/
public class Test4 {
private void testClassForName(String name) throws ClassNotFoundException{
Class c=Class.forName(name);
}
private void testNewInstance(String name) throws ClassNotFoundException, InstantiationException, IllegalAccessException{
Class c=Class.forName(name);
Object obj=c.newInstance();
System.out.println(obj);
}
public static void main(String[] args)throws Exception {
Test4 t=new Test4();
t.testClassForName("test1.B");
new B();
new B();
}
}
class A{
private int aj;
{
aj=20;
System.out.println("A成員初始化塊");
}
private static int ai;
static {
ai=10;
System.out.println("A靜態(tài)初始化塊");
}
public A(){
System.out.println("A構(gòu)造函數(shù)");
}
}
class B extends A{
private static int bi;
static {
bi=30;
System.out.println("B靜態(tài)初始化塊");
}
private int bj;
{
bj=40;
System.out.println("B成員初始化塊");
}
public B(){
System.out.println("B構(gòu)造函數(shù)");
}
}
* Test4.java
*
* Created on 2007-9-21, 9:33:31
*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package test1;
/**
*
* @author hadeslee
*/
public class Test4 {
private void testClassForName(String name) throws ClassNotFoundException{
Class c=Class.forName(name);
}
private void testNewInstance(String name) throws ClassNotFoundException, InstantiationException, IllegalAccessException{
Class c=Class.forName(name);
Object obj=c.newInstance();
System.out.println(obj);
}
public static void main(String[] args)throws Exception {
Test4 t=new Test4();
t.testClassForName("test1.B");
new B();
new B();
}
}
class A{
private int aj;
{
aj=20;
System.out.println("A成員初始化塊");
}
private static int ai;
static {
ai=10;
System.out.println("A靜態(tài)初始化塊");
}
public A(){
System.out.println("A構(gòu)造函數(shù)");
}
}
class B extends A{
private static int bi;
static {
bi=30;
System.out.println("B靜態(tài)初始化塊");
}
private int bj;
{
bj=40;
System.out.println("B成員初始化塊");
}
public B(){
System.out.println("B構(gòu)造函數(shù)");
}
}
在代碼里面我們總共有三個(gè)類,一個(gè)是做測(cè)試用的Test4,一個(gè)是A,一個(gè)是A的子類B,我們?cè)贏和B類里面都有很多輸出,一個(gè)是靜態(tài)初始化的輸出,一個(gè)是成員初始化的輸出,一個(gè)是在構(gòu)造函數(shù)里面的輸出,從這些輸出我們可以知道代碼的執(zhí)行順序,以上代碼運(yùn)行輸出如下:
A靜態(tài)初始化塊
B靜態(tài)初始化塊
A成員初始化塊
A構(gòu)造函數(shù)
B成員初始化塊
B構(gòu)造函數(shù)
A成員初始化塊
A構(gòu)造函數(shù)
B成員初始化塊
B構(gòu)造函數(shù)
從上面我們可以看出,A和B的靜態(tài)初始化塊只被執(zhí)行了一次,也就是類的對(duì)象將要被生成的時(shí)候,它會(huì)執(zhí)行,并且執(zhí)行的順序如下:父類的靜態(tài)成員,子類的靜態(tài)成員,父類的成員變量和構(gòu)造方法,子類的成員變量和構(gòu)造方法.當(dāng)再用這個(gè)類生成對(duì)象的時(shí)候,靜態(tài)的部份就不再被調(diào)用了.因?yàn)殪o態(tài)是類的所有實(shí)例所共享的,所以它在整個(gè)虛擬機(jī)的生命周期內(nèi)只執(zhí)行一次.
如果我們加上一個(gè)t.testClassForName("test1.B");放在main函數(shù)的最后面,我們會(huì)發(fā)現(xiàn)輸出還是和剛剛一樣,沒(méi)有任何改變,這個(gè)時(shí)候,我們知道,當(dāng)我們調(diào)用Class.forName(name);的時(shí)候,類是不會(huì)自動(dòng)初始化的,它默認(rèn)只是把這個(gè)類的字節(jié)碼讀入內(nèi)存,但是并沒(méi)有初始化這個(gè)類.只有我們調(diào)用了newInstance()的時(shí)候,它才會(huì)被初始化.在這里我們?cè)龠@樣試一下:把A和B生成的class文件去掉,然后再分別調(diào)用Class.forName和new B(),看看會(huì)怎么樣,我們會(huì)發(fā)現(xiàn)當(dāng)我們調(diào)用Class.forName的時(shí)候,當(dāng)我們要for的Name找不到的時(shí)候,只會(huì)拋出ClassNotFoundException,注意,它只是一個(gè)異常而已,而當(dāng)我們new B()的時(shí)候,B的class文件卻被我們刪掉了,那就事大了,那就將拋出NoClassDefFoundError,呵呵,它就是一個(gè)Error了,這點(diǎn)區(qū)別我們可要注意啦,當(dāng)我們?cè)谧鲞@些事情的時(shí)候,一個(gè)只要捕獲異常就可以了,一個(gè)卻需要捕獲一個(gè)Error,一般來(lái)說(shuō),Error級(jí)別的錯(cuò)誤是不希望程序員去捕獲的.了解了類的基本加載順序以及加載機(jī)制后,對(duì)我們了解JAVA是有一定的幫助的.好了,先講這些吧,有關(guān)類的加載機(jī)制以后再繼續(xù)分享:)
盡管千里冰封
依然擁有晴空
你我共同品味JAVA的濃香.