久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

ClassLoader(1)ClassLoader和Class

 碧海山城 2010-08-08

1.java源碼和class文件Class

  java源碼都被編譯為class文件,,jvm真正啟動之后還是要找到對應的Class,,靠的就是ClassLoader


2.啟動以及三個ClassLoader

當我們通過命令java XXMain.class的時候,java.exe根據(jù)我們的設置找到了JRE,,接著找到JRE鐘的jvm.dll,,真正的java虛擬機,最后載入這個動態(tài)函數(shù)庫,,啟動Java虛擬機,虛擬機一啟動,,首先做一些初始化的動作,,獲得系統(tǒng)參數(shù)等,初始化完成后,,就會產生第一個ClassLoader,,即Bootstrap Loader,這個Loader除了初始化動作之外,,最重要的就是載入定義在sun.misc命名空間下的Launcher,java中的ExtClassLoader,,因為是內部類,所以編譯后變成(第2個)Launcher$ExtClassLoader,,并設定其parentnull,,代表父載入器為Bootstrap,。接著Bootstarp又載入Launcher中的AppClassLoader(第三個)LauncherAppClassLoader,,并設定parent為之前的ExtClassLoader實例,。

關于三者的詳細詳細關系以及委托加載機制,請看 ClassLoader(2)Boot,、App,、Ext、線程加載器
 

3.獲取Class的ClassLoader

Class類是一個樣板,,實例就是樣板產生的實體,,在Java中,每個類都繼承了Object,,Object里的getClass方法,,就是用來取得某個特定實體所屬類的參考,它指向一個Class.class的實例,,Class本身構造函數(shù)是私有的,,所以不能自己產生實例,它是在類第一次載入內存的時候建立的,,每個實例內部都會記錄這些個Class的位置

 

Class的實例是在類第一次載入內存的時候建立的

(關于Class實例的內存分布,,可以參考我的GC文章)


基本上,我們可以把每個Class的實體,,當做是某個類,,在內存中的代理人,每次我們需要查詢某個類的資料,,比如field,、method,就可以使用它,,事實上,,Java的反射機制,就大量的利用Class類,,它的大部分方法都是本地方法,。通過Class的newInstance方法,可以得到一個實例,。


Java中,,每個Class都是由一個ClassLoader實體來載入的,每個Class實體中,,都記錄它的ClassLoader的實體,,(如果是null,并不是代表不是沒有ClassLoader,,而是代表他是由bootstrap loader,,或者叫root loader載入的,,因為他們不是java寫的,所以沒有實體),。

 

只要取得Class的實例就可以通過getClassLoader取得對應的ClassLoader,,

ClassLoader cl=Vector.class.getClassLoader();

       class c=cl.loadClass("Hello");

c.newInstance();

這種方式也不會初始化靜態(tài)代碼塊,和Class.forName第二個參數(shù)為false幾乎是一樣的,。


4.幾種載入Class的方法

雖然我們知道ClassLoader用來載入Class,,但是我們調用Class.forName()的時候以及new的時候是怎么載入的?


4.1 new Object()

class A(){

   public A(){

     new B();

  }

}

當A里面new B的時候發(fā)生了什么,?Class A一定是先載入了,,不管是AppClassLoader還是自定義的UrlClassLoader,那么在A new B的時候,,會按照以下順序來確定B使用的ClassLoader:(參看 jvm spc5.3

1.The Java virtual machine uses one of three procedures to create class or interface C denoted by N:

  • 1.1If N denotes a nonarray class or an interface, one of the two following methods is used to load and thereby create C:

    • 1.1.1If D was defined by the bootstrap class loader, then the bootstrap class loader initiates loading of C (§5.3.1).

    • 1.1.2If D was defined by a user-defined class loader, then that same user-defined class loader initiates loading of C (§5.3.2).

  • 1.2Otherwise N denotes an array class. An array class is created directly by the Java virtual machine (§5.3.3), not by a class loader. However, the defining class loader of D is used in the process of creating array class C.

如果B不是數(shù)組,,,那么采用A的加載器加載(Boot或者用戶自定義加載器)

如果B是數(shù)組,,那活在虛擬機直接創(chuàng)建代表數(shù)組的class,,而不是通過classloader載入什么的,當然從使用角度來看,,B還是由A的加載器加載的


    4.2 Class.forName()

其實,,在使用JDBC的時候,就是使用Class.forName來動態(tài)裝入類別的,,Class有兩個forName方法:


Public static Class forName(String className

Public static Class forName(String name,boolean initializa,ClassLoader loader)


如果沒有傳入ClassLoader,,那么誰使用ClassLoader.getCallerClassloader,我的理解其實就是調用它的當前類加載器


最終,,他們都是鏈接到了原生方法: (所以他使用的ClassLoader還是比較明確的,,可以自定義也可以使用當前類加載器)

    private static native Class forName0(String name, boolean initialize,ClassLoader loader) throws ClassNotFoundException;


一種說法,靜態(tài)初始化塊在類第一次載入的時候才會被調用僅一次,,可是實際上當我們第二個參數(shù)為false的時候,,只會在第一次載入類,但是不會調用靜態(tài)初始化塊,,而是等到第一次實例化的時候,,靜態(tài)初始化才會被調用。


    4.3 ClassLoader.loadClass()

         所有的loader都是ClassLoader的子類,,他的loadClsss方法就可以用來真正找到類,他的大致流程如下:


 

   4.4 ClassLoader.defineClass

         有些時候并不是知道了ClassName,,而是得到了一個byte數(shù)組(一般是網絡傳輸過來的情況,,取代了從磁盤讀取字節(jié)流的形式),這時候就可以調用defineClass方法直接得到Class


  4.5 unsafe.defineClass

api:Class sun.misc.Unsafe.defineClass(String arg0, byte[] arg1, int arg2, int arg3, ClassLoader arg4, ProtectionDomain arg5)
使用: unsafe.defineClass(className, btraceCode, 0, btraceCode.length, classLoader, null);

這種方式可以得到Class,,而且還可以指定classloader

4.6 ObjectInputStream.readObject()

在一些序列化傳輸中,,會直接調用readObject來讀取對象,,但是對象序列化本身只帶一些實例和類描述信息,還是需要在接收端有對應的Class,,序列化的格式參考:java默認序列化格式

序列化信息中包含了是哪個class名,,

 private ObjectStreamClass readNonProxyDesc(boolean unshared) 

throws IOException {

......

     .....

ObjectStreamClass readDesc = null;

try {

    readDesc = readClassDescriptor();

catch (ClassNotFoundException ex) {

    throw (IOException) new InvalidClassException(

"failed to read class descriptor").initCause(ex);

}

Class cl = null;

ClassNotFoundException resolveEx = null;

bin.setBlockDataMode(true);

try {

    if ((cl = resolveClass(readDesc)) == null) {

resolveEx = new ClassNotFoundException("null class");

    }

catch (ClassNotFoundException ex) {

    resolveEx = ex;

}

..........

}

可以看到從序列化信息中,讀取到的是Class的一些描述信息,,ObjectStreamClass,,他包含必須的自我發(fā)現(xiàn)的一些必要信息:http://docs.oracle.com/javase/6/docs/api/java/io/ObjectStreamClass.html 

可以覆蓋次方法,根據(jù)className,,從遠程或者其他地方獲取類信息,。

5.自定義ClassLoader


URLClassLoader的實例來幫我們載入所需要的類,載入之前,,告訴URLClassLoader去哪個地方尋找類,,URL可以指向網絡上的任何位置


TODO


6.被載入多次的類


        參考下面的代碼:


URL url=new URL("file:/C:/jar1.jar");

URLClassLoader ucl=new URLClassLoader(new URL[]{url});

Class c=ucl.loadClass("bhsc.hello.TestAction");

ActionInterface a1=(ActionInterface)c.newInstance();

a1.action();

//,Thread.currentThread().getContextClassLoader()

URL url1=new URL("file:/C:/jar1.jar");

URLClassLoader u2=new URLClassLoader(new URL[]{url1});

Class c1=u2.loadClass("bhsc.hello.TestAction");

c.newInstance();

ActionInterface a2=(ActionInterface)c1.newInstance();

a2.action();

System.out.println(ClassLoaderTest.class.getClassLoader());

System.out.println(ActionInterface.class.getClassLoader());

System.out.println(ucl.getClass().getClassLoader());

System.out.println(c.getClass().getClassLoader());

System.out.println(c.getClassLoader());

System.out.println(a1.getClass().getClassLoader());

System.out.println("==============================");

System.out.println(u2.getClass().getClassLoader());

System.out.println(c1.getClass().getClassLoader());

System.out.println(c1.getClassLoader());

System.out.println(a2.getClass().getClassLoader());

結果:

static init

TestAction

static init

TestAction

sun.misc.Launcher$AppClassLoader@19821f

sun.misc.Launcher$AppClassLoader@19821f

null

null

java.net.URLClassLoader@c17164

java.net.URLClassLoader@c17164

==============================

null

null

java.net.URLClassLoader@ca0b6

java.net.URLClassLoader@ca0b6

ActionInterface是一個接口,TestAction是實現(xiàn)類,,項目不能引用到TestAction(如果能夠引用到TestAction的話又是另一種結果,,待會再說)。


可以從結果看到,,類的static塊被調用了兩次,,也就是說在一個虛擬機中,相同的類被載入了兩次,,

ClassLoaderTestAppClassLoader(又稱為SystemLoader,,系統(tǒng)載入器)所載入,URLURLCLassLoader,,為null,,表示由BootstrapLoader載入,它不是java寫的,,所以沒有實例,。兩個TestAction,分別由不同的ClassLoader實例載入,。

    本站是提供個人知識管理的網絡存儲空間,,所有內容均由用戶發(fā)布,不代表本站觀點,。請注意甄別內容中的聯(lián)系方式,、誘導購買等信息,謹防詐騙,。如發(fā)現(xiàn)有害或侵權內容,,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多