zoukankan      html  css  js  c++  java
  • 类加载器ClassLoader的理解

      最近在做一个热加载Class的小组件,这个组件需要对类加载器ClassLoader有所了解,我就顺便借这个机会把学到的一点皮毛与大家分享一下。

     从Class文件开始

    ClassLoader,顾名思义就是类加载器。简单的说就是把Class文件加载到JVM中,之后程序就能正常的运行了。

    我们平时写的代码都是.java格式的文件,但是这个文件是不能够直接运行的。比如下面这个简单的测试程序Test.java

    1 public class Test {
    2 
    3     public static void main(String[] args) {
    4         System.out.println("Testing");
    5     }
    6 }

    在文件夹下看,就是这么一个文件:

    我们在命令行下编译一下这个Java文件:

    1 javac Test.java 

    然后就可以在目录下看到生成的class文件,也就是JVM可以识别运行的文件。

    Java自带的类加载器

    Java自带有三个类加载器:

    Bootstrap ClassLoader:主要加载核心类库,%Java_HOME%lib 下的rt.jar、resources.jar、charsets.jar和class等,总之就是jdk安装目录下lib目录下的一些核心jar包。

    Extention ClassLoader 扩展的类加载器,主要加载目录%JRE_HOME%libext目录下的jar包和class文件,就是JRE安装目录下lib目录下ext目录下的jar和class文件。

    Appclass Loader也称为SystemAppClass应用程序加载器 加载当前应用的classpath的所有类,这个就是很好理解了,就是我们平时自己写的项目类路径下的类。

    双亲委派机制

    接下来我先祭出一张常见的图:

    双亲委派机制的意思是:一个类加载器遇到一个加载类的请求,首先不会自己去加载,而是看自己的父加载器能否加载这个类,然后一级一级往上传直到遇到能够加载这个类的加载器。

    简单可以形容为一家几口吃苹果:
    小明:爸爸,这苹果你吃吗?
    小明的爸爸:我先问问你爷爷,爸,这苹果你吃吗?
    小明的爷爷:你们真孝顺,那我就恭敬不如从命啦。

    如果遇到顶层的父类加载器无法加载,该怎么办?这个时候,就往下找,找到第一个能加载这个类的加载器
    小明:爸爸,这苹果你吃吗?
    小明的爸爸:我先问问你爷爷,爸,这苹果你吃吗?
    小明的爷爷:牙不好啦,我不吃啦你们吃吧。
    小明的爸爸:好的,我的牙口还不错,那我就吃了。

    那么为什么需要一个机制呢,原因主要是为了避免类加载程序的混乱。

    比如Java官方指定了一个java.lang.String类,然后你自己又重新写了一个java.lang.String类的类。这个时候,你想import一个String类型,就没有办法判断到底这个String是哪个String了。

    当然这边要多说一句,父类加载器不等于父类,也就是上面的三个类加载器并不是继承关系。

    自定义ClassLoader

    刚刚那张图大家应该已经发现了,除了三个系统自带的ClassLoader以外,最底层还有几个自定义的类加载器。

    没错,原来的类加载器只是按照特定的方式加载指定目录下的jar包,那么如果你想按照自己的要求加载一些东西呢?这就需要你自己去定义一个classloader了。

    比如以我为例,我希望可以多次重新加载同一个Class。

    ClassLoader中,加载Class的方法是loadClass(),我们可以看一下源码:

     1    protected Class<?> loadClass(String name, boolean resolve)
     2         throws ClassNotFoundException
     3     {
     4         synchronized (getClassLoadingLock(name)) {
     5             // First, check if the class has already been loaded
     6             Class<?> c = findLoadedClass(name);
     7             if (c == null) {
     8                 long t0 = System.nanoTime();
     9                 try {
    10                     if (parent != null) {
    11                         c = parent.loadClass(name, false);
    12                     } else {
    13                         c = findBootstrapClassOrNull(name);
    14                     }
    15                 } catch (ClassNotFoundException e) {
    16                     // ClassNotFoundException thrown if class not found
    17                     // from the non-null parent class loader
    18                 }
    19 
    20                 if (c == null) {
    21                     // If still not found, then invoke findClass in order
    22                     // to find the class.
    23                     long t1 = System.nanoTime();
    24                     c = findClass(name);
    25 
    26                     // this is the defining class loader; record the stats
    27                     sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
    28                     sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
    29                     sun.misc.PerfCounter.getFindClasses().increment();
    30                 }
    31             }
    32             if (resolve) {
    33                 resolveClass(c);
    34             }
    35             return c;
    36         }
    37     }

    可是在ClassLoader中的加载class的方法loadClass()中,有一个  findLoadedClass() 方法来判断Class是否已经被加载的操作,不符合要求,而且loadClass()方法中也会按照双亲委派去找寻父类加载器,不符合要求。(看不懂源码没有关系,里面的英文还是可以看懂的嘛哈哈)

    于是我的步骤

    1. 编写一个类继承自ClassLoader抽象类。 
    2. 复写它的findClass()方法,直接调用findClass()来找寻Class文件,而不是loadClass()。
    3. findClass()方法中调用defineClass(),defineClass()将class二进制内容转换成Class对象并加载进内存。 

    这样子,就实现了我的重复加载Class的目的。

  • 相关阅读:
    ionic localstorage
    angular 中文鏈接
    把jqmobi 變成jQuery 的插件 從此使用jQuery
    jqmobi 的一些設置
    ionic ngcordova map 地圖
    ionic pull to refresh 下拉更新頁面
    json 對象的序列化
    鍵盤彈出,頁面佈局被推上去了.....
    Cordova V3.0.0中config.xml配置文件的iOS Configuration
    android ios 只能輸入數字 不能輸入小數點的 函數 cordova
  • 原文地址:https://www.cnblogs.com/jing-daye/p/6647233.html
Copyright © 2011-2022 走看看