Java的类加载器

此文仅做学习笔记,参考之http://www.ibm.com/developerworks/cn/java/j-lo-classloader/,讲得很好。

以前基本上没有怎么接触过类加载器,最近,想研究下JVM,所以找了一些资料进行了学习,感觉收获颇多。

  重点:父类委托机制,最终定义类的加载器负责启动引用类的加载过程。

  Java中的类加载器分为4种(上文中定义为2种,其实是一样的),分别是

  1:BootstrapClassLoader:这个是根类加载器,由c++写成,负责加载/lib/rt.jar中的文件

  2:ExtClassLoader:扩展类加载器,负责加载/lib/ext/*.jar的文件

  3:AppClassLoader:系统类加载器,负责加载classpath下的class文件

  4:自定义类加载器

  其中BootstrapClassLoader是没办法进行访问的,在代码中进行测试总是返回null。

  类加载的过程捋顺清楚后还是比较好理解的,先看下JDK-7的源代码:

protected Class<?> loadClass(String name, boolean resolve)
       throws ClassNotFoundException
   {
       synchronized (getClassLoadingLock(name)) {
           // First, check if the class has already been loaded
           Class c = findLoadedClass(name);
           if (c == null) {
               long t0 = System.nanoTime();
               try {
                   if (parent != null) {
                       c = parent.loadClass(name, false);
                   } else {
                       c = findBootstrapClassOrNull(name);
                   }
               } catch (ClassNotFoundException e) {
                   // ClassNotFoundException thrown if class not found
                   // from the non-null parent class loader
               }
 
               if (c == null) {
                   // If still not found, then invoke findClass in order
                   // to find the class.
                   long t1 = System.nanoTime();
                   c = findClass(name);
 
                   // this is the defining class loader; record the stats
                   sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                   sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                   sun.misc.PerfCounter.getFindClasses().increment();
               }
           }
           if (resolve) {
               resolveClass(c);
           }
           return c;
       }
   }
非常清楚,一个类如果已经被加载过了,那么将去缓存中进行加载,否则,判断类加载器是否有父类加载器,如果有,让父类去加载,如果父类加载成功,则直接resolve,否则执行findClass方法,如果再找不到,则由子类加载器来进行查找,如果找到了就resolve,其中看下findClass方法的源码:

protected Class<?> findClass(String name) throws ClassNotFoundException {
        throw new ClassNotFoundException(name);
    }

在ClassLoader类中此类没有做任何实质性的事情,因此需要此类的子类进行实现。所以到这里,我们就对类的加载过程比较清楚了。在这某些场景下是很有必要的,比如说Object类,其实你在工程中完全可以创建一个java.lang.Object类,如果这个类不是由根类加载器加载的,那么我们可以加载很多个版本的Object类,这样我们所有集成Object类就陷入了混乱。所以这样的类在进行加载时参照Class c = findLoadedClass(name);

  关于两个类是否相同的问题我觉得引文中讲得很好啦,对于一个类,JVM的判断方式是根据是否由同一个类加载器来加载的,比如说class T由两个类加载器同时加载,即使类的内容都相同,JVM仍然会认为这两个类是不同的,原因在于类加载加载类时会添加很多额外的信息,这个就相当于人为的添加了一个命名空间。

  引文中有一部分是线程上下文类加载器,这个是比较好理解的,为什么说某些SPI无法找寻到实现类,因为加载接口的类加载器是根加载器,而最终定义类的加载器负责启动引用类的加载过程,所以根加载器是无法找寻到SPI的实现类的,因此,线程上下文类加载器就起作用了。

  关于自定义类加载器,为什么不复写loadClass方法,而只建议写findClass方法,原因如上解释。

  关于OSGI,学习到现在其实也没怎么接触过,记得淘宝的林昊大神出过一本书自己也只是翻了翻,就不献丑了,有兴趣的读者可以阅读原文。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值