日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

c 自定义实现string类 clear_有关类加载器的总结

發布時間:2024/9/30 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c 自定义实现string类 clear_有关类加载器的总结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

對于java開發來說,classLoader往往是容易被我們忽視的一個重要知識點。而classLoader對java的發展也有很大的影響。例如。

  • 早期的applet應用,通過網絡遠程加載class文件。
  • web容器對應用class文件的加載。
  • spi機制的支持。
  • 等等。
  • 學習知識往往帶著疑問去學習,效果可能會比較好。接下來我帶著幾個問題來解答classLoader有關的疑問。

  • 什么是classLoader?為什么需要classLoader?
  • 什么是雙親委派? 為什么需要雙親委派?
  • 什么是contextClassLoader? 為什么需要ContextClassLoader?
  • classLoader用于什么場景?什么情況下需要什么classLoader?
  • 接下來就一一解答上面的疑問。以我的學習方式來說,對這塊知識點用反證的思維來理解比較簡單。

    分析classLoader之前,我們先直接class的加載過程,并且下面方法跟加載過程一一對應。

    類加載過程 , copy from http://www.importnew.com/25295.html
    • 加載class文件,從jvm中對應的Class文件。
    • 接著驗證Class是否合法。即對class進行有效性、合法性驗證。
    • 準備階段的工作:為類變量分配內存并初始化值,這里的初初始化值并不是設置用戶指定的值。例如。
    public static int age = 12;
    public static String name = "wang007";
    初始化值,先將int = 0; name = null;在接下來的初始化階段, 再講 int = 12, name = "wang007";

    其他階段可參考JVM 類加載機制詳解 - ImportNew;

    1. 什么是classLoader?為什么需要classLoader?

    classLoader是用于加載我們編譯好的class文件到jvm中。在ClassLoader這個類中能看到相關重要的方法。下面我就列舉幾個比較重要的方法來解釋一下。

    public

    loadClass方法,根據 java全限定名稱 加載 很明顯,該方法對應類加載過程的 加載階段

    findClass方法, 該方法是需要子類去實現的方法, 根據 java全限定名稱 加載 class文件。 可以從本地文件系統加載, 也可以通過網絡從任一服務器中加載。 對于需要自實現classLoader的話,一般只需要實現該方法即可。

    resolveClass方法,根據loadClass方法加載好的Class對象, 進行連接工作。 即驗證、準備、解析方法。

    還有defineClass方法,將用byte[]二進制數組 創建class對象。final方法無法拓展,在findClass方法中,獲取byte[],調用defineClass方法創建Class對象。


    2 什么是雙親委派? 為什么需要雙親委派?

    說到雙親委派模型,那么必須先介紹BootstrapClassLoader,ExtClassLoader,AppClassLoader.

    • BootstrapClassLoader負責加載rt.jar包中的class文件。 C++寫的,所以在java不可見,用null引用代替。
    • ExtClassLoader負責加載ext目錄的jar包中的class文件。
    • AppClassLoader負責加載classpath下的class文件,即我們編寫的java文件編譯成的class文件。

    所謂的雙親委派模型是指加載class時, 先讓父classLoader加載class,如果父classLoader加載不到,再自己加載。 這里的“父”, 不是指繼承關系,而是指屬性指定的“父”ClassLoader。

    AppClassLoader的父加載器是ExtClassLoader,ExtClassLoader的父加載器是BootstrapClassLoader。

    public 在ClassLoader這個類中, 用parent屬性指定當前classLoader的“父”加載器。 AppClassLoader,ExtClassLoader都是繼承該類。

    為什么需要雙親委派?

    雙親委派模型是為了保證應用安全的,確保rt.jar包內的代碼只由BootstrapClassLoader加載的。 例如我們在代碼中用AppClassLoader(即SystemClassLoader)加載String.class,AppClassLoader會讓ExtClassLoader加載的, ExtClassLoader會讓BootClassLoader加載,因為String.class在rt.jar中,所以BootstrapClassLoader會加載成功, 返回到 ExtClassLoader, 最后返回到AppClassLoader中。

    如果我們用自實現的ClassLoader加載String.class(這個String.class我加點后門代碼),不通過雙親委派模型,直接自己加載。是可以加載出來的,但是跟BootstrapClassLoader加載出來的String不是同一個。因為ClassLoader不同, 加載出來的Class對象也不同。 如果讓自定義ClassLoader加載出來的String 賦值給BootClassLoader,會報ClassCastException.

    這里展示雙親委派的關鍵代碼

    //這里指定 resolve = false,所以ClassLoader加載class是不會導致類的初始化的

    有疑惑點的地方,再詳情說說。

  • 整個加載過程,都是鎖住的,確保指定對當前類的全限定名加載一個線程在執行。
  • 如果自定義classLoader設置parent = null, 那么就會跳ext路徑下類加載,可能會導致沖突。 所以自定義ClassLoader一般指定 parent = appClassLoader。

  • 3. 什么是contextClassLoader? 為什么需要ContextClassLoader?

    ContextClassLoader就是通過thread.getContextClassLoader()方法獲取的ClassLoader。 我知道,如果我換做你,聽到這種解釋, 我都想錘死我自己。哈哈哈。

    上面說的雙親委派模型, 看似天衣無縫,其實未必。我覺得ContextClassLoader恰恰是為雙親委派模型擦屁股的角色。

    當我們需要加載一個Class的對象,從自定義ClassLoader,到appClassLoader,再到ExtClassLoader,最后到BootstrapClassLoader。沒問題, 很順利。這是從下到上加載。 但是反過來,當從上到下加載的時候,這個變得是一個不可能完成的任務。為了彌補這個缺陷, 特定設計的ContextClassLoader。

    但可能又會有疑問了, 什么情況下, 會出現從上到下加載呢?

    我舉個很實用,但是又幾乎用不到的例子吧(是不是像極了好吃又吃不飽的東西。233333) spi機制。 這里我就不展開講spi了。有興趣的話,自行搜索資料學習,基本大部分框架都會用到spi。

    我們都知道,SUN是個一流的公司,因為一流的公司賣標準嘛, 雖然這個一流的公司已經死了。 在rt.jar包中, 定義了很多spi接口, JDBC,JNDI等等。 但是spi接口的實現一般都是以第三方jar的方式提供到classpath下。 例如, JDBC spi的接口由BootstrapClassLoader加載, 但是有些spi接口中會加載spi實現包的類,而BootstrapClassLoader只能加載rt.jar的類, 不能classPath下的類,所以通過thread.getContextClassLoader方法獲取到ClassLoader(這個一般是AppClassLoader)。然后通過這個classLoader在spi 接口中加載其實現。

    補充一個知識點。如果類A引用類B,且類B還未加載, 那么用加載類A的類加載器加載類B。

    我找了下,只找到了DriverManger這個類下,通過spi機制加載Driver實現。(例如mysql driver)只不過這個用的是ClassLoader.getSystemClassLoader()方法, 效果跟contextClassLoader差不多。都是為了加載第三方實現類。

    public

    接下來來看下。ContextClassLoader是怎么來的。

    public

    在Launcher的構造方法中,獲取ExtClassLoader,如果是第一次調用,就會創建一個ExtClassLoader。 獲取再獲取AppClassLoader。第一次調用, 也會創建一個。 最后將appClassLoader設置到Thread。

    我們知道,main方法是java程序的入口,而main方法所在的類也是有AppClassLoader加載的。 而AppClassLoader正在來自于Launcher類,所以在Launcher類在main方法運行之前就創建好了。

    為啥AppClassLoader也叫SystemClassLoader呢? 因為:

    public

    在ClassLoader類中的getSystemClassLoader方法,就是從launcher類中獲取的appClassLoader,并設置到ClassLoader類的靜態屬性中。 所以AppClassLoader也叫SystemClassLoader

    ContextClassLoader的傳播。

    //thread的構造方法中調用init方法

    在新建一個線程的時候,就是會把原來線程所在的ClassLoader設置到新的線程中。 就這么一直傳播下去。 如果我們改變當前線程的ContextClassLoader,那么當前線程上新建Thread的ContextClassLoader就是改變后的。

    例如。

    public

    所以ContextClassLoader的傳播是通過新建Thread的時候,把當前線程的ContextClassLoader設置到新線程中。

    同時還有類似方式傳播的東西。inheritableThreadLocals。 也叫可繼承的ThreadLocal。有興趣的話,可以自行查找資料。InheritableThreadLocal。跟ThreadLocal差不多的作用。

    4. ClassLoader的運用場景。

    其實ClassLoader,我們直接或間接的用了很多。例如Tomcat需要加載項目中的class文件。 按照默認提供的ClassLoader是不夠的。必須自定義ClassLoader來加載項目中的class文件。還有熱啟動機制,想必也是用到了自定義ClassLoader。

    最后再解決一個疑問點。 Class.forName與ClassLoader.loadClass 的區別?

    前面介紹了ClassLoader的loadClass方法,是不會觸發類的初始化操作的。

    而Class.forName是會觸發類的初始化操作。

    public

    在forName0方法中,第一個參數就是類名,第二個參數是是否初始化類, 第三個參數是指定ClassLoader。 所以在forName方法中, 指定了需要初始化, 還指定了ClassLoader為當前調用類的ClassLoader。

    其實Class.forName還有一個重載方法,可以指定是否初始化,和ClassLoader

    public

    好了,有關classLoader的知識就總結到這里了。 有些點由于篇幅關系就沒有深入下去了。

    總結

    以上是生活随笔為你收集整理的c 自定义实现string类 clear_有关类加载器的总结的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。