qileilove

          blog已經轉移至github,大家請訪問 http://qaseven.github.io/

          Java基礎加強之類加載器

           學習概述:本模塊深入講解了Java類加載方面的知識,Java類加載器和類加載機制以及類加載原理
            學習目標:掌握類加載機制和原理,能夠獨立開發自己的類加載器。
            1.類的加載
            什么是類加載? 類加載是指將類的class文件讀入內存,并為之創建一個Java.lang.Class對象,也就是說當程序中使用任何類時,系統都會為之建立一個java.lang.Class對象。
            類加載器負責加載所有類,系統為所有被載入內存中的類生成一個java.lang.Class實例。一旦一個類被載入JVM中,同一個類不會再被再次載入。
            思考問題:怎么樣才算同一個類?
            當JVM啟動時,會形成三個類加載器組成的原始類加載器層次結構:
            【BootStrap ClassLoader】根類加載器 這是一個特殊的加載器,他并不是有Java編寫,而是JVM自身實現的
            【Extension Classloader】擴展類加載器
            【System Classloader】系統類加載器
            類加載器的父子關系:
            實驗獲得類加載器以及了解類加載器的層次結構:
          public  class ClassloaderDemo{
          public static  void main(String[] args){
          System.out.printlb(ClassLoaderDemo.class.getClassLoader().getName());
          System.out.println(System.class.getClassloader());
          ClassLoader classloader = ClassLoaderDemo.class.getClassLoader());
          while(loader!=null){
          System.out.println(loader.getClass().getName());
          loader=loader.getParent();
          }
          }
            注意:程序會拋出異常,因為JVM根類加載器不是Java類。
            2.類的加載機制,如圖所示:
            <1>全盤負責:所謂全盤負責,就是說當一個類加載器負責加載某個Class的時候,該Class所依賴的和引用的其他Class也將由該類加載器負責載入,除非顯式使用另外一個                            類加載器來實現載入。
            <2>父類委托:意思是先讓父類加載器試圖加載該Class,只有父類加載器無法加載該類是才嘗試從自己的路徑中加載該類。
            <3>緩存機制:緩存機制將會保證所有被加載過的Class都會被緩存,當程序中需要使用某個Class時,類加載器先從緩存中搜索該Class,只有當緩存中不存在該Class對象              時,系統才重新讀取該類對應的二進制數據。這就是為什么我們修改Class后,JVM必須重新啟動,修改才生效的原因。
            類加載器的父子關系:用戶類加載器—>系統類加載器—>擴展類加載器—>根類加載器
            類加載機制:
            <1>當JVM需要加載一個類是,到底指派哪個類加載器去加載呢?
            首先當前線程的類加載器去加載線程中的第一個類,如果A類中引用了B類,JVM將使用加載A類的加載器來加載B類,最后還可以調用ClassLoader。loadeClass方法指定        某個類加載器去加載某個類。
            <2>每個類加載器在加載類時,先委托給其上級加載器。
            注意兩點:
            當所有的祖宗類加載器都沒有加載到類,回到發起類加載器,還加載不了,那么程序將拋出ClassNotFoundExcetpion,而不是去找發起類加載器的兒子,因為沒有                     getChild ()方法,即使有,那么選擇哪一個兒子加載器呢?
            面試題:能不能自己寫一個類叫Java.lang.System?
            答案:可以寫,但是因為JVM委托機制的存在,會先找到JVM根類加載器,我自己寫也可以,那么我要拋開委托加載機制,我自己指定一個ClassLoader。


           3.自定義類加載器
            JVM中除了根類加載器之外的所有類加載器都是classloader的子類實例,我們完全可以通過擴展ClassLoader的子類,并重寫ClassLoader所包含的的方法來實現自定義類       加載器,ClassLoader有兩個關鍵的方法:loadClass(),findClass()。
            不過我們一般推薦重寫findClass()方法,而不是loadClass()方法,因為重寫findClass()可以避免覆蓋默認類加載器的父類委托,緩存機制兩種策略。
            下面是我自己編寫的一個類加載器:
          package snippet;
          import java.io.File;
          import java.io.FileInputStream;
          import java.io.FileNotFoundException;
          import java.io.IOException;
          import java.io.InputStream;
          /**
          *
          * @author Administrator
          *自定義類加載器
          */
          public class MyClassLoader extends ClassLoader {
          // 獲取java源文件的二進制碼
          public byte[] getBytes(String filename){
          File file = new File(filename);
          InputStream ips=null;
          byte[] b = new byte[(int) file.length()];
          try {
          ips = new FileInputStream(file);
          int raw =ips.read(b);
          if(raw!=file.length()){
          throw new IOException("無法完整讀取文件");
          }
          } catch (FileNotFoundException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
          } catch (IOException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
          }
          finally{
          if(ips!=null){
          try {
          ips.close();
          } catch (IOException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
          }
          }
          }
          return b;
          }
          public boolean compile(String javaFile){
          System.out.println("正在編譯");
          Process p=null;
          try {
          //調用系統javac命令
          p=Runtime.getRuntime().exec("javac" + javaFile);
          try {
          p.waitFor();
          } catch (InterruptedException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
          }
          } catch (IOException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
          }
          int ret = p.exitValue();
          return ret==0;
          }
          @Override
          protected Class<?> findClass(String name) {
          Class<?> clazz=null;
          String fileStub = name.replace(".", "/");
          String javaFileName = fileStub + ".java";
          String classFileName = fileStub + ".class";
          File javaFile = new File(javaFileName);
          File classFile = new File(classFileName);
          //如果java源文件存在并且class文件不存在,或者java源文件比class文件修改的時間晚
          if(javaFile.exists()&&(!classFile.exists()||javaFile.lastModified()>classFile.lastModified())){
          if(!compile(javaFileName)||!classFile.exists()){
          try {
          throw new ClassNotFoundException("未發現class文件");
          } catch (ClassNotFoundException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
          }
          }
          //如果class文件已經存在,那么直接生成字節碼
          if(classFile.exists()){
          byte[] b = getBytes(classFileName);
          clazz = defineClass(name, b, 0, b.length);
          }
          //如果為空,標明加載失敗
          if(clazz==null){
          try {
          throw new ClassNotFoundException(name);
          } catch (ClassNotFoundException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
          }
          }
          }
          return clazz;
          }
          }
            上面代碼重寫了findClass方法,通過重寫該方法就可以實現自定義的類加載機制。
            學習總結:1.了解了JVM三種類加載器(根類加載器,系統類加載器,擴展類加載器),明白了三種類加載器的作用和范圍
            2.學習了JVM三種類加載機制(父類委托,緩存,全盤負責)
            3.學習了如何自定義類加載器,通過繼承ClassLoader類,特別要注意兩個關鍵方法:loadClass()和findClass()兩種方法的機制和不同。

          posted on 2013-12-24 11:50 順其自然EVO 閱讀(181) 評論(0)  編輯  收藏


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          <2013年12月>
          24252627282930
          1234567
          891011121314
          15161718192021
          22232425262728
          2930311234

          導航

          統計

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 贺兰县| 亳州市| 琼结县| 额尔古纳市| 龙井市| 南乐县| 扬中市| 日喀则市| 铜梁县| 阿鲁科尔沁旗| 安国市| 扎兰屯市| 万安县| 上蔡县| 晋宁县| 五华县| 仁寿县| 红桥区| 容城县| 青海省| 西藏| 遂宁市| 富民县| 兴国县| 西乌珠穆沁旗| 锡林郭勒盟| 司法| 中山市| 包头市| 汝南县| 健康| 诸城市| 贡山| 闽侯县| 宜川县| 辽宁省| 舞阳县| 越西县| 奇台县| 阜平县| 彰武县|