类加载器详解

<h1>
    <span class="link_title"><a href="/jiangwei0910410003/article/details/17733153">
    Java高新技术第一篇:类加载器详解            
    </a></span>
</h1>
    <div class="article_manage clearfix">
    <div class="article_r">
        <span class="link_postdate">2014-01-01 14:45</span>
        <span class="link_view" title="阅读次数">11316人阅读</span>
        <span class="link_comments" title="评论次数"> <a href="#comments" onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_pinglun'])">评论</a>(10)</span>
        <span class="link_collect tracking-ad" data-mod="popu_171"> <a href="javascript:void(0);" onclick="javascript:collectArticle('Java%e9%ab%98%e6%96%b0%e6%8a%80%e6%9c%af%e7%ac%ac%e4%b8%80%e7%af%87%ef%bc%9a%e7%b1%bb%e5%8a%a0%e8%bd%bd%e5%99%a8%e8%af%a6%e8%a7%a3','17733153');return false;" title="收藏">收藏</a></span>
         <span class="link_report"> <a href="#report" onclick="javascript:report(17733153,2);return false;" title="举报">举报</a></span>

    </div>
</div>
<div class="embody" style="display:none" id="embody">
    <span class="embody_t">本文章已收录于:</span>
    <div class="embody_c" id="lib" value="{&quot;err&quot;:0,&quot;msg&quot;:&quot;ok&quot;,&quot;data&quot;:[]}"></div>
</div>
<style type="text/css">        
        .embody{
            padding:10px 10px 10px;
            margin:0 -20px;
            border-bottom:solid 1px #ededed;                
        }
        .embody_b{
            margin:0 ;
            padding:10px 0;
        }
        .embody .embody_t,.embody .embody_c{
            display: inline-block;
            margin-right:10px;
        }
        .embody_t{
            font-size: 12px;
            color:#999;
        }
        .embody_c{
            font-size: 12px;
        }
        .embody_c img,.embody_c em{
            display: inline-block;
            vertical-align: middle;               
        }
         .embody_c img{               
            width:30px;
            height:30px;
        }
        .embody_c em{
            margin: 0 20px 0 10px;
            color:#333;
            font-style: normal;
        }
</style>
<script type="text/javascript">
    $(function () {
        try
        {
            var lib = eval("("+$("#lib").attr("value")+")");
            var html = "";
            if (lib.err == 0) {
                $.each(lib.data, function (i) {
                    var obj = lib.data[i];
                    //html += '<img src="' + obj.logo + '"/>' + obj.name + "&nbsp;&nbsp;";
                    html += ' <a href="' + obj.url + '" target="_blank">';
                    html += ' <img src="' + obj.logo + '">';
                    html += ' <em><b>' + obj.name + '</b></em>';
                    html += ' </a>';
                });
                if (html != "") {
                    setTimeout(function () {
                        $("#lib").html(html);                      
                        $("#embody").show();
                    }, 100);
                }
            }      
        } catch (err)
        { }
        
    });
</script>
  <div class="category clearfix">
    <div class="category_l">
       <img src="http://static.blog.csdn.net/images/category_icon.jpg">
        <span>分类:</span>
    </div>
    <div class="category_r">
                <label onclick="GetCategoryArticles('1819961','jiangwei0910410003','top','17733153');">
                    <span onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_fenlei']);">Java<em>(34)</em></span>
                  <img class="arrow-down" src="http://static.blog.csdn.net/images/arrow_triangle _down.jpg" style="display:inline;">
                  <img class="arrow-up" src="http://static.blog.csdn.net/images/arrow_triangle_up.jpg" style="display:none;">
                    <div class="subItem">
                        <div class="subItem_t"><a href="http://blog.csdn.net/jiangwei0910410003/article/category/1819961" target="_blank">作者同类文章</a><i class="J_close">X</i></div>
                        <ul class="subItem_l" id="top_1819961">                            
                        </ul>
                    </div>
                </label>                    
    </div>
</div>
<script type="text/javascript" src="http://static.blog.csdn.net/scripts/category.js"></script>  
    <div class="bog_copyright">         
        <p class="copyright_p">版权声明:本文为博主原创文章,未经博主允许不得转载。</p>
    </div>

首先来了解一下字节码和class文件的区别:

我们知道,新建一个Java对象的时候,JVM要将这个对象对应的字节码加载到内存中,这个字节码的原始信息存放在classpath(就是我们新建Java工程的bin目录下)指定的目录下的.class文件,类加载需要将.class文件导入到硬盘中,经过一些处理之后变成字节码在加载到内存中。

下面来看一下简单的例子:

  1. package com.loadclass.demo;  
  2.   
  3. import java.util.Date;  
  4. import java.util.List;  
  5.   
  6. /** 
  7.  * 测试类 
  8.  * @author Administrator 
  9.  */  
  10. public class ClassLoaderTest {  
  11.   
  12.     @SuppressWarnings("rawtypes")  
  13.     public static void main(String[] args){  
  14.         //输出ClassLoaderText的类加载器名称  
  15.         System.out.println("ClassLoaderText类的加载器的名称:"+ClassLoaderTest.class.getClassLoader().getClass().getName());  
  16.         System.out.println("System类的加载器的名称:"+System.class.getClassLoader());  
  17.         System.out.println("List类的加载器的名称:"+List.class.getClassLoader());  
  18.           
  19.         ClassLoader cl = ClassLoaderTest.class.getClassLoader();  
  20.         while(cl != null){  
  21.             System.out.print(cl.getClass().getName()+"->");  
  22.             cl = cl.getParent();  
  23.         }  
  24.         System.out.println(cl);  
  25.     }  
  26.       
  27. }  
输出结果:

可以看到,ClassLoaderTest类时由AppClassLoader类加载器加载的。下面就来了解一下JVM中的各个类加载器,同时来解释一下运行的结果。

Java虚拟机中类加载器:

Java虚拟机中可以安装多个类加载器,系统默认三个主要的类加载器,每个类负责加载特定位置的类:

BootStrap,ExtClassLoader,AppClassLoader

类加载器也是Java类,因为Java类的类加载器本身也是要被类加载器加载的,显然必须有第一个类加载器不是Java类,这个正是BootStrap,使用C/C++代码写的,已经封装到JVM内核中了,而ExtClassLoader和AppClassLoader是Java类。

看一下类加载器的属性结构图:


Java虚拟机中的所有类加载器采用具有父子关系的树形结构进行组织,在实例化每个类加载器对象的时候,需要为其指定一个父级类加载器对象或者默认采用系统类加载器为其父级类加载

类加载器的委托机制:

当Java虚拟机要加载第一个类的时候,到底派出哪个类加载器去加载呢?

(1). 首先当前线程的类加载器去加载线程中的第一个类(当前线程的类加载器:Thread类中有一个get/setContextClassLoader(ClassLoader cl);方法,可以获取/指定本线程中的类加载器)

(2). 如果类A中引用了类B,Java虚拟机将使用加载类A的类加载器来加载类B

(3). 还可以直接调用ClassLoader.loadClass(String className)方法来指定某个类加载器去加载某个类

每个类加载器加载类时,又先委托给其上级类加载器当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则会抛出ClassNotFoundException,不是再去找发起者类加载器的儿子,因为没有getChild()方法。例如:如上图所示: MyClassLoader->AppClassLoader->Ext->ClassLoader->BootStrap.自定定义的MyClassLoader1首先会先委托给AppClassLoader,AppClassLoader会委托给ExtClassLoader,ExtClassLoader会委托给BootStrap,这时候BootStrap就去加载,如果加载成功,就结束了。如果加载失败,就交给ExtClassLoader去加载,如果ExtClassLoader加载成功了,就结束了,如果加载失败就交给AppClassLoader加载,如果加载成功,就结束了,如果加载失败,就交给自定义的MyClassLoader1类加载器加载,如果加载失败,就报ClassNotFoundException异常,结束。


对着类加载器的层次结构图和委托加载原理,解释先前的运行的结果

因为System类,List,Map等这样的系统提供jar类都在rt.jar中,所以由BootStrap类加载器加载,因为BootStrap是祖先类,不是Java编写的,所以打印出class为null

对于ClassLoaderTest类的加载过程,打印结果也是很清楚的。


现在再来做个试验来验证上面的结论:

首先将ClassLoaderTest.java打包成.jar文件(这个步骤就不说了吧,很简单的)

然后将.jar文件拷贝到Java的安装目录中的Java/jre7/lib/ext/目录下


这时候你在运行ClassLoaderTest类,结果如下:


这时候就发现了ClassLoaderTest的类加载器变成了ExtClassLoader,这时候就说明了上面的结论是正确的,因为ExtClassLoader加载jre/ext/*.jar,首先AppClassLoader类加载器发请求给ExtClassLoader,然后ExtClassLoader发请求给BootStrap,但是BootStrap没有找到ClassLoaderTest类,所以交给ExtClassLoader处理,这时候ExtClassLoader在my_lib.jar中找到了ClassLoaderTest类,所以就把它加载了,然后结束了。

其实采用这种树形的类加载机制的好处就在于:

能够很好的统一管理类加载,首先交给上级,如果上级有了,就加载,这样如果之前已经加载过的类,这时候在来加载它的时候只要拿过来用就可以了,无需二次加载了


下面来看一下怎么定义我们自己的一个类加载器MyClassLoader:

自己可以定义类加载器,要将自己定义的类加载器挂载到系统类加载器树上,在ClassLoader的构造方法中可以指定parent,没有指定的话,就使用默认的parent


这里看一下默认的parent是使用getSystemClassLoader方法获取的,这个方法的源码没有找到,所以只能通过代码来测试一下了

  1. System.out.println("默认的类加载器:"+ClassLoaderTest.class.getClassLoader().getSystemClassLoader());  
输入结果为:


所以默认的都是将自定义的类加载器挂载到系统类加载器的最低端AppClassLoader,这个也是很合理的。


自定义的类加载器必须继承抽象类ClassLoader然后重写findClass方法,其实他内部还有一个loadClass方法和defineClass方法,这两个方法的作用是:

loadClass方法的源代码:

  1. public Class<?> loadClass(String name) throws ClassNotFoundException {  
  2.        return loadClass(name, false);  
  3.    }  
再来看一下loadClass(name,false)方法的源代码:

  1. protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException{  
  2.          //加上锁,同步处理,因为可能是多线程在加载类  
  3.          synchronized (getClassLoadingLock(name)) {  
  4.              //检查,是否该类已经加载过了,如果加载过了,就不加载了  
  5.              Class c = findLoadedClass(name);  
  6.              if (c == null) {  
  7.                  long t0 = System.nanoTime();  
  8.                  try {  
  9.                      //如果自定义的类加载器的parent不为null,就调用parent的loadClass进行加载类  
  10.                      if (parent != null) {  
  11.                          c = parent.loadClass(name, false);  
  12.                      } else {  
  13.                          //如果自定义的类加载器的parent为null,就调用findBootstrapClass方法查找类,就是Bootstrap类加载器  
  14.                          c = findBootstrapClassOrNull(name);  
  15.                      }  
  16.                  } catch (ClassNotFoundException e) {  
  17.                      // ClassNotFoundException thrown if class not found  
  18.                      // from the non-null parent class loader  
  19.                  }  
  20.   
  21.                  if (c == null) {  
  22.                      // If still not found, then invoke findClass in order  
  23.                      // to find the class.  
  24.                      long t1 = System.nanoTime();  
  25.                      //如果parent加载类失败,就调用自己的findClass方法进行类加载  
  26.                      c = findClass(name);  
  27.   
  28.                      // this is the defining class loader; record the stats  
  29.                      sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);  
  30.                      sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);  
  31.                      sun.misc.PerfCounter.getFindClasses().increment();  
  32.                  }  
  33.              }  
  34.              if (resolve) {  
  35.                  resolveClass(c);  
  36.              }  
  37.              return c;  
  38.          }  
  39.      }  
    <div id="digg" articleid="17733153">
        <dl id="btnDigg" class="digg digg_disable" onclick="btndigga();">
           
             <dt>顶</dt>
            <dd>24</dd>
        </dl>
       
          
        <dl id="btnBury" class="digg digg_disable" onclick="btnburya();">
          
              <dt>踩</dt>
            <dd>1</dd>               
        </dl>
        
    </div>
 <div class="tracking-ad" data-mod="popu_222"><a href="javascript:void(0);">&nbsp;</a>   </div>
<div class="tracking-ad" data-mod="popu_223"> <a href="javascript:void(0);">&nbsp;</a></div>
<script type="text/javascript">
            function btndigga() {
                $(".tracking-ad[data-mod='popu_222'] a").click();
            }
            function btnburya() {
                $(".tracking-ad[data-mod='popu_223'] a").click();
            }
        </script>
<div style="clear:both; height:10px;"></div>


    <div class="similar_article" style="">
            <h4>我的同类文章</h4>
            <div class="similar_c" style="margin:20px 0px 0px 0px">
                <div class="similar_c_t">
                            <label class="similar_cur">
                                <span style="cursor:pointer" onclick="GetCategoryArticles('1819961','jiangwei0910410003','foot','17733153');">Java<em>(34)</em></span>
                            </label>
                </div>
               
                <div class="similar_wrap tracking-ad" data-mod="popu_141" style="max-height:195px;">
                    <a href="http://blog.csdn.net" style="display:none">http://blog.csdn.net</a>
                    <ul class="similar_list fl"><li><em>•</em><a href="http://blog.csdn.net/jiangwei0910410003/article/details/40709457" id="foot_aritcle_40709457undefined9872781153581331" target="_blank" title="Java虚拟机解析篇之---垃圾回收器">Java虚拟机解析篇之---垃圾回收器</a><span>2014-11-02</span><label><i>阅读</i><b>8459</b></label></li> <li><em>•</em><a href="http://blog.csdn.net/jiangwei0910410003/article/details/38303229" id="foot_aritcle_38303229undefined6722388951661094" target="_blank" title="数据结构和算法设计专题之---单链表中在指定的节点前面插入以及删除一个节点">数据结构和算法设计专题之---单链表中在指定的节点前面插入以及删除一个节点</a><span>2014-07-30</span><label><i>阅读</i><b>2234</b></label></li> <li><em>•</em><a href="http://blog.csdn.net/jiangwei0910410003/article/details/38269117" id="foot_aritcle_38269117undefined09114136771028858" target="_blank" title="数据结构和算法设计专题之---判断单链表中是否有环,环的长度,环的入口节点">数据结构和算法设计专题之---判断单链表中是否有环,环的长度,环的入口节点</a><span>2014-07-29</span><label><i>阅读</i><b>2858</b></label></li> <li><em>•</em><a href="http://blog.csdn.net/jiangwei0910410003/article/details/38235315" id="foot_aritcle_38235315undefined703371427540247" target="_blank" title="数据结构和算法设计专题之---求子数组和的最大值">数据结构和算法设计专题之---求子数组和的最大值</a><span>2014-07-28</span><label><i>阅读</i><b>1702</b></label></li> <li><em>•</em><a href="http://blog.csdn.net/jiangwei0910410003/article/details/37997899" id="foot_aritcle_37997899undefined7836805888311487" target="_blank" title="Ubuntu中的解压缩文件的方式">Ubuntu中的解压缩文件的方式</a><span>2014-07-20</span><label><i>阅读</i><b>3667</b></label></li> <li><em>•</em><a href="http://blog.csdn.net/jiangwei0910410003/article/details/37937749" id="foot_aritcle_37937749undefined5547662853006825" target="_blank" title="数据结构和算法设计专题之---24点游戏(穷举法和递归法)">数据结构和算法设计专题之---24点游戏(穷举法和递归法)</a><span>2014-07-18</span><label><i>阅读</i><b>2569</b></label></li> </ul>

                    <ul class="similar_list fr"><li><em>•</em><a href="http://blog.csdn.net/jiangwei0910410003/article/details/40616223" id="foot_aritcle_40616223undefined7052951709194668" target="_blank" title="Java虚拟机解析篇之---内存模型">Java虚拟机解析篇之---内存模型</a><span>2014-11-02</span><label><i>阅读</i><b>5019</b></label></li> <li><em>•</em><a href="http://blog.csdn.net/jiangwei0910410003/article/details/38302913" id="foot_aritcle_38302913undefined36136141388562537" target="_blank" title="数据结构和算法设计专题之---判断两个链表是否相交并找出交点">数据结构和算法设计专题之---判断两个链表是否相交并找出交点</a><span>2014-07-30</span><label><i>阅读</i><b>1729</b></label></li> <li><em>•</em><a href="http://blog.csdn.net/jiangwei0910410003/article/details/38261783" id="foot_aritcle_38261783undefined9757742813796053" target="_blank" title="数据结构和算法设计专题之---八大内部排序">数据结构和算法设计专题之---八大内部排序</a><span>2014-07-29</span><label><i>阅读</i><b>2471</b></label></li> <li><em>•</em><a href="http://blog.csdn.net/jiangwei0910410003/article/details/38024403" id="foot_aritcle_38024403undefined6796594969173155" target="_blank" title="数据结构和算法设计专题之---二分查找(Java版)">数据结构和算法设计专题之---二分查找(Java版)</a><span>2014-07-21</span><label><i>阅读</i><b>1819</b></label></li> <li><em>•</em><a href="http://blog.csdn.net/jiangwei0910410003/article/details/37996723" id="foot_aritcle_37996723undefined5760348151322146" target="_blank" title="Ubuntu下安装JDK图文解析">Ubuntu下安装JDK图文解析</a><span>2014-07-20</span><label><i>阅读</i><b>17132</b></label></li> </ul>
                <a href="http://blog.csdn.net/jiangwei0910410003/article/category/1819961" class="MoreArticle">更多文章</a></div>
            </div>
        </div>    
<script type="text/javascript">
    $(function () {
        GetCategoryArticles('1819961', 'jiangwei0910410003','foot','17733153');
    });
</script>
posted @ 2017-02-01 22:07  jobs-lgy  阅读(197)  评论(0编辑  收藏  举报