Java类加载器机制用法代码解析

  

做Java开发,对于类加载器的机制是必须要熟悉的基础知识,本文针对Java类加载器的机制做一个简要的总结。因为不同的JVM的实现不同,本文所描述的内容均只限于Hotspot JVM。

  

本文将会从JDK默认的提供的类加载器,双亲委托模型,如何自定义类加载器以及Java中打破双亲委托机制的场景四个方面入手去讨论和总结一下。

  


  

  

<强> JDK默认提供了如下几种类加载器

  

Bootstrp装载机
  

  

Bootstrp加载器是用c++语言写的,它是在Java虚拟机启动后初始化的,它主要负责加载% JAVA_HOME %/jre/lib, -Xbootclasspath参数指定的路径以及中% JAVA_HOME %/jre/类的类。

  

ExtClassLoader
  

  

Bootstrp装载机加载ExtClassLoader,并且将ExtClassLoader的父加载器设置为Bootstrp加载程序。ExtClassLoader是用Java写的,具体来说就是sun.misc.Launcher ExtClassLoader美元,ExtClassLoader主要加载% JAVA_HOME %/jre/lib/ext,此路径下的所有类目录以及java.ext.dirs系统变量指定的路径中类库。

  

AppClassLoader
  

  

Bootstrp装载机加载完ExtClassLoader后,就会加载AppClassLoader,并且将AppClassLoader的父加载器指定为ExtClassLoader.AppClassLoader也是用Java写成的,它的实现类是sun.misc.Launcher AppClassLoader美元,另外我们知道类加载器中有个getSystemClassLoader方法,此方法返回的正是AppclassLoader.AppClassLoader主要负责加载类路径所指定的位置的类或者是jar文档,它也是Java程序默认的类加载器。

  


  

  

Java中类加载器的加载采用了双亲委托机制,采用双亲委托机制加载类的时候采用如下的几个步骤:

  

当前类加载器首先从自己已经加载的类中查询是否此类已经加载,如果已经加载则直接返回原来已经加载的类。

  

每个类加载器都有自己的加载缓存,当一个类被加载了以后就会放入缓存,等下次加载的时候就可以直接返回了。

  

当前类加载器的缓存中没有找到被加载的类的时候,委托父类加载器去加载,父类加载器采用同样的策略,首先查看自己的缓存,然后委托父类的父类去加载,一直到bootstrp classLoader。

  

当所有的父类加载器都没有加载的时候,再由当前的类加载器加载,并将其放入它自己的缓存中,以便下次有加载请求的时候直接返回。

  

说到这里大家可能会想,Java为什么要采用这样的委托机制?理解这个问题,我们引入另外一个关于类加载器的概念“命名空间”,它是指要确定某一个类,需要类的全限定名以及加载此类的类加载器来共同确定。也就是说即使两个类的全限定名是相同的,但是因为不同的类加载器加载了此类,那么在JVM中它是不同的类。明白了命名空间以后,我们再来看看委托模型。采用了委托模型以后加大了不同的类加载器的交互能力,比如上面说的,我们JDK本生提供的类库,比如hashmap, linkedlist等等,这些类由bootstrp类加载器加载了以后,无论你程序中有多少个类加载器,那么这些类其实都是可以共享的,这样就避免了不同的类加载器加载了同样名字的不同类以后造成混乱。

  


  

  

Java除了上面所说的默认提供的类加载器以外,它还容许应用程序可以自定义类加载器,那么要想自定义类加载器我们需要通过继承java.lang.ClassLoader来实现,接下来我们就来看看在自定义类加载器的时候,我们需要注意的几个重要的方法:

  

<强> 1。loadClass方法

  

loadClass方法声明         公共Class<& # 63;比;loadClass(字符串名称)抛出ClassNotFoundException   之前      

上面是loadClass方法的原型声明,上面所说的双亲委托机制的实现其实就是在此方法中实现的。下面我们就来看看此方法的代码来看看它到底如何实现双亲委托的。

  

loadClass方法实现         公共Class<& # 63;比;loadClass(字符串名称)抛出ClassNotFoundException   {   返回loadClass(名称、假);   }      

从上面可以看出loadClass方法调用了loadcClass(名称、假)方法,那么接下来我们再来看看另外一个loadClass方法的实现。

  

类loadClass(字符串名称,布尔解决)

        保护同步Class<& # 63;比;loadClass(字符串名称,布尔解决)抛出ClassNotFoundException   {//首先,检查是否已经加载的类   类c=findLoadedClass(名称);//检查类是否已经被加载过了   如果(c==null)   {   尝试{   如果(父!=null) {   c=父母。loadClass(名称、假);//如果没有被加载,且指定了父类加载器,则委托父加载器加载。   其他}{   c=findBootstrapClass0(名称);//如果没有父类加载器,则委托引导加载器加载}   }   抓住(ClassNotFoundException e) {//如果仍然没有找到,然后调用findClass//找到该类。   c=findClass(名称);//如果父类加载没有加载到,则通过自己的findClass来加载。}   }   如果(解决)   {   resolveClass (c);   }   返回c;   }

Java类加载器机制用法代码解析