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

从Class文件开始

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

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

 public class Test {

     public static void main(String[] args) {
System.out.println("Testing");
}
}

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

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

 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%\lib\ext目录下的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(),我们可以看一下源码:

    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;
}
}

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

于是我的步骤

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

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

最新文章

  1. C# Entity Framework并发处理
  2. Python全栈开发day9
  3. 正则表达式匹配a标签的href
  4. print函数
  5. tar
  6. 如何做好APP测试?
  7. MongoDB 基础命令行
  8. [前端 4] 使用Js实现图片上传预览
  9. UVA 10537 The Toll! Revisited 过路费(最短路,经典变形)
  10. 模拟接听电话的方法,兼容华为android5.0以上设备
  11. ENC28J60 + M430G2553,用uip搭建http服务器,解决“在XP系统下可以访问,在Win7下不能访问”的问题
  12. Linux下配置SSL (转)
  13. 如何捕获winform程序全局异常?
  14. 微信小程序开发教程目录
  15. minimun depth of binary tree
  16. PHP将汉字转为拼音
  17. Oracle Database 11g安装及报错处理(win7)
  18. Java中static、final、static final的区别【转】
  19. LiveCharts文档-4基本绘图-3其他
  20. 使用TVTK库创建一个矩形视图

热门文章

  1. ansible-playbook权限提升多种方式
  2. PAT B1038 统计同成绩学生超时问题
  3. JavaScript学习总结(六)
  4. eclipse环境配置,字体大小,代码智能提示,JSP页面默认字符集修改
  5. 107.JsonResponse
  6. Ansible-大保健
  7. 使用IDEA搭建SSM,小白教程
  8. Java使用Sftp实现对跨服务器上传、下载、打包、写入相关操作
  9. 新手学习Web前端的三个高效学习方法,基础要重视
  10. 使用GitHub Pages服务进行域名URL转发