詳細(xì)介紹java類加載的表現(xiàn)形式
Java中的類是動(dòng)態(tài)加載的,我們先看一下我們常用的類加載方式,先有一個(gè)感性的認(rèn)識(shí),才能進(jìn)一步深入討論,類加載無非就是下面三種方式。
- class A{}
 - class B{}
 - class C{}
 - public class Loader{
 - public static void main(String[] args) throws Exception{
 - Class aa=A.class;
 - Class bb=Class.forName("B");
 - Class cc=ClassLoader.getSystemClassLoader().loadClass("C");
 - }
 - }
 
我們先看.class字面量方式,很多人可能不知道這種方式,因?yàn)檫@種用法不是一般java語法。通過javap我們可以發(fā)現(xiàn),這種方式的大致等價(jià)于定義了一個(gè)靜態(tài)成員變量
- static Class class$0;(后面的編號(hào)是增長的)
 
你可以試圖再定義一個(gè) static Class class$0,應(yīng)該會(huì)收到一個(gè)編譯錯(cuò)誤(重復(fù)定義)。
- Class aa=A.class;
 
就相當(dāng)于
- if(class$0==null){
 - try{
 - Class.forName("A");
 - }
 - cacth(ClassNotFoundException e){
 - throw new NoClassDefFoundError(e);
 - }
 - }
 - Class aa=class$0;
 
可以很清楚的看到,這種類的字面量定義其實(shí)不是加載類的方式,而是被編譯器處理了,實(shí)質(zhì)上是使用了Class.forName方法,但是使用這種方式有一個(gè)很大的好處就是不用處理異常,因?yàn)榫幾g器處理的時(shí)候如果找不到類會(huì)拋出一個(gè)NoClassDefFoundError。也許你覺得需要處理ClassNotFoundException這種異常,事實(shí)上99%的情況下我們可以把這種異常認(rèn)為是一個(gè)錯(cuò)誤。所以大部分情況我們使用這種方式會(huì)更簡(jiǎn)潔。
最常用的方式就是Class.forName方式了,這也是一個(gè)通用的上層調(diào)用。這個(gè)方法有兩個(gè)重載,可能很多人都忽略了第二個(gè)方法。
- public static Class forName(String name) throws ClassNotFoundException
 - public static Class forName(String name, boolean initialize,ClassLoader loader)
 - throws ClassNotFoundException
 
第二個(gè)方法后面多了兩個(gè)參數(shù),第二個(gè)參數(shù)表示是否初始化,第三個(gè)參數(shù)為指定的類加載器。
在上面的例子中:
- Class bb=Class.forName("B");
 
等價(jià)于
- Class bb=Class.forName("B",true,Loader.class.getClassLoader());
 
這里要詳細(xì)說一下這個(gè)類的初始化這個(gè)參數(shù),如果這個(gè)參數(shù)為false的話,類中的static成員不會(huì)被初始化,static語句塊也不會(huì)被執(zhí)行。
也就是類雖然被加載了,但是沒有被初始化,不過在第一次使用時(shí)仍然會(huì)初始化。所以我們有時(shí)候會(huì)看到Class.forName("XXX").newInstance()這樣的語句,為什么這里要?jiǎng)?chuàng)建一個(gè)不用的實(shí)例呢?不過是為了保證類被初始化(兼容以前的系統(tǒng))。
其實(shí)第二個(gè)方法是比較難用的,需要指定類加載器,如果不指定而且又沒有安裝安全管理器的化,是無法加載類的,只要看一下具體的實(shí)現(xiàn)就明白了。
最本質(zhì)的方式當(dāng)然是直接使用ClassLoader加載了,所有的類最終都是通過ClassLoader加載的,
- Class cc=ClassLoader.getSystemClassLoader().loadClass("C");
 
這里通過使用系統(tǒng)類加載器來加載某個(gè)類,很直接的方式,但是很遺憾的是通過這種方式加載類,類是沒有被初始化的(也就是初始化被延遲到真正使用的時(shí)候).不過我們也可以借鑒上面的經(jīng)驗(yàn),加載后實(shí)例化一個(gè)對(duì)象Class cc=ClassLoader.getSystemClassLoader().loadClass("C").newInstance()。
這里使用了系統(tǒng)類加載器,也是最常用的類加載器,從classpath中尋找要加載的類。java中默認(rèn)有三種類加載器:引導(dǎo)類加載器,擴(kuò)展類加載器,系統(tǒng)類加載器。java中的類加載有著規(guī)范的層次結(jié)構(gòu),如果我們要了解類加載的過程,需要明確知道哪個(gè)類被誰加載,某個(gè)類加載器加載了哪些類等等,就需要深入理解ClassLoader的本質(zhì)。
以上只是類加載的表面的東西,我們還將討論深層次的東西。















 
 
 






 
 
 
 