类加载器ClassLoader的理解
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了类加载器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%\\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()中,有一个 findLoadedClass() 方法来判断Class是否已经被加载的操作,不符合要求,而且loadClass()方法中也会按照双亲委派去找寻父类加载器,不符合要求。
我的步骤
- 编写一个类继承自ClassLoader抽象类。
- 复写它的
findClass()
方法,直接调用findClass()来找寻Class文件,而不是loadClass()。 - 在
findClass()
方法中调用defineClass(),defineClass()将class二进制内容转换成Class对象
。
这样子,就实现了我的热加载Class的目的。
以上是关于类加载器ClassLoader的理解的主要内容,如果未能解决你的问题,请参考以下文章