类加载器ClassLoader的理解
最近在做一个热加载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()方法中也会按照双亲委派去找寻父类加载器,不符合要求。(看不懂源码没有关系,里面的英文还是可以看懂的嘛哈哈)
于是我的步骤
- 编写一个类继承自ClassLoader抽象类。
- 复写它的
findClass()方法,直接调用findClass()来找寻Class文件,而不是loadClass()。 - 在
findClass()方法中调用defineClass(),defineClass()将class二进制内容转换成Class对象并加载进内存。
这样子,就实现了我的重复加载Class的目的。
类加载器ClassLoader的理解的更多相关文章
- 深入理解Java类加载器(ClassLoader) (转)
转自: http://blog.csdn.net/javazejian/article/details/73413292 关联文章: 深入理解Java类型信息(Class对象)与反射机制 深入理解Ja ...
- 深入理解Java类加载器(ClassLoader)
深入理解Java类加载器(ClassLoader) Java学习记录--委派模型与类加载器 关于Java类加载双亲委派机制的思考(附一道面试题) 真正理解线程上下文类加载器(多案例分析) [jvm解析 ...
- Java虚拟机学习(5):类加载器(ClassLoader
类加载器 类加载器(ClassLoader)用来加载 class字节码到 Java 虚拟机中.一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源文件在经过 Javac之后就被转换成 ...
- jvm之java类加载机制和类加载器(ClassLoader),方法区结构,堆中实例对象结构的详解
一.类加载或类初始化:当程序主动使用某个类时,如果该类还未被加载到内存中,则JVM会通过加载.连接.初始化3个步骤来对该类进行初始化.如果没有意外,JVM将会连续完成3个步骤. 二.类加载时机: 1 ...
- Java 类加载器(ClassLoader)
类加载器 ClassLoader 什么是类加载器? 通过一个类的全限定名来获取描述此类的二进制字节流这个动作放到Java虚拟机外部去实现, 以便让应用程序自己决定如何去获取所需要的类.实现这个动作的代 ...
- 类加载器ClassLoader
上篇文章说到,Class类可以通过一个类的全限定名去加载类,那么底层是如何去加载的呢?这就是我们今天要聊的类加载器ClassLoader,其可以通过一个类的全限定名来获取描述此类的二进制字节流,也即是 ...
- 类加载器ClassLoader之jar包隔离
小引子 最近做了一个根据同一模块的不同jar版本做同时测试的工具,感觉挺有意思,特此记录. 类加载器(ClassLoader)是啥? 把类加载阶段中的"通过一个类的全限定名(博主注:绝对路径 ...
- Java类加载器ClassLoader总结
JAVA类装载方式,有两种: 1.隐式装载, 程序在运行过程中当碰到通过new 等方式生成对象时,隐式调用类装载器加载对应的类到jvm中. 2.显式装载, 通过class.forname()等方法,显 ...
- Java类加载器(ClassLoader)
类加载的机制的层次结构 每个编写的”.java”拓展名类文件都存储着需要执行的程序逻辑,这些”.java”文件经过Java编译器编译成拓展名为”.class”的文件,”.class”文件中保存着Jav ...
随机推荐
- Cobub无码埋点关键技术的实现
随着大数据时代的到来,数据采集也已经变的越来越重要.前端埋点作为一个比较成熟的数据接入手段被广泛应用着.目前埋点分为两种方式,有码与无码埋点.有码埋点比较容易理解,即调用SDK的API,在代码中插入埋 ...
- CPU构架和工作原理
-- CPU -- -- CPU 由三部分组成:时钟:控制单元:算术逻辑单元 -- -- -- 时钟:对CPU内部操作与系统其他硬件进行同步: -- -- -- 控制单元:控制机器指令的执行顺序: - ...
- python刷LeetCode:1.两数之和
难度等级:简单 题目描述: 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但是,你不 ...
- [SWPU2019]Web1
0x00 知识点 bypass information_schema 参考链接: https://www.anquanke.com/post/id/193512 进行bypass之前先了解一下mysq ...
- target到底是什么?
xmake是一个基于Lua的轻量级现代化c/c++的项目构建工具,主要特点是:语法简单易上手,提供更加可读的项目维护,实现跨平台行为一致的构建体验. 本文主要详细讲解下,如果在一个项目中维护和生成多个 ...
- 配置Action
配置Action 实现了Action类后,就可以在struts.xml中配置该Action类了.配置Action就是让Struts2 知道哪个Action处理哪个请求,也就是完成用户请求和Action ...
- 【按位dp】1出现的次数
l-r1出现的次数 注意端点处理 垃圾算法书 垃圾代码毁我青春 自己研究写了写 #include <iostream> #include <string> #include & ...
- 数学之美_正态分布(Python代码)
1 在概率统计中,我们针对某个事件当中各个样本发生的概率的频率进行统计,用一个函数的形式写出的这个概率的频率函数就叫做分布函数. 2 分布函数顾名思义,就是某个连续事件发生频率的汇总表示.再直白一点儿 ...
- Linux中PATH、 LIBRARY_PATH、 LD_LIBRARY_PATH和ROS_PACKAGE_PATH
PATH 保存可执行文件程序路径,我们命令行中每一句能运行的命令都是系统先通过PATH来找到命令执行文件所在的位置,再运行这个命令. 实验:执行echo $PATH 能看到当前环境PATH都是配置了哪 ...
- 浙江省赛 ZOJ - 4033
题意: 第一行给出T代表有几个测试样例, 第二行给出n代表有几个人, 第三行给出一个由0和1组成的字符串,0代表女生,1代表男生. 并且第i个人有i个宝石. 现在要把这些人分为四组,G1 G2 两组是 ...