ClassLoader如何加载class

简介: ClassLoader如何加载class


ClassLoader是经常出现又让很多人望而却步的词,所以我将试图用最浅显易懂的方式来说一下ClassLoader,希望对不了解该机制的朋友们能起到一点点的作用。

要深入了解ClassLoader,首先就要知道ClassLoader是用来干什么的,顾名思义,它就是用来加载Class文件到JVM(Java Virtual Machine(Java虚拟机)的缩写)。以供程序使用的。我们知道,Java程序可以动态加载类定义,而这个动态加载的机制就是通过ClassLoader来实现的,所以可想而知ClassLoader的重要性如何。

看到这里,可能有的朋友会想到一个问题,那就是既然ClassLoader是用来加载类到JVM中的,那么ClassLoader又是如何被加载的呢,难道他不是Java的类吗?

没有错,在这里确实有一个ClassLoader不是用Java语言所编写的,而是JVM实现的一部分,这个ClassLoader就是bootstrap classloader(启动类加载器),这个ClassLoader在JVM运行的时候加载Java核心的API以满足Java程序最基本的需求,其中就包括用户自定义的ClassLoader,这里所谓的用户自定义是指通过Java程序实现的ClassLoader,一个是ExtClassLoader,这个ClassLoader是用来加载Java的扩展API的,也就是/lib/ext中的类。另一个是AppClassLoader,这个ClassLoader是用来加载用户机器上CLASSPATH设置目录中的class的,通常在没有指定ClassLoader的情况下,我们程序员自定义的类就由该ClassLoader进行加载。

当运行一个程序的时间,JVM启动,运行bootstrap classloader,该ClassLoader加载Java核心API(ExtClassLoader和APPClassLoader也在此时被加载),然后调用ExtClassLoader加载扩展API,最后APPClassLoader加载CLASSPATH目录下定义的class,这就是一个程序最基本的加载流程。

上面大概解释了一下ClassLoader的作用以及一个最基本的加载流程,下面来解释一下ClassLoader加载的方式,说到ClassLoader的加载方式,不得不解释一下ClassLoader在这里使用了双亲委托模式进行类加载。

每一个自定义ClassLoader都必须继承ClassLoader这个抽象类,而每个ClassLoader都会有一个parent ClassLoader,我们可以看一下ClassLoader这个抽象类中有一个getParent()方法,这个方法用来返回当前ClassLoader的parent,注意,这个parent不是指定的被继承的类,而是在实例化该ClassLoader时指定的一个ClassLoader,如果这个parent为null,那么就默认该ClassLoader的parent是bootstrap classloader,这个parent有什么用呢?

我们可以考虑这样一种情况,假设我们自定义了一个ClientDefClassLoader,我们使用这个自定义的ClassLoader加载java.lang.String,那么这里String是否会被这个ClassLoader加载呢?事实上,java.lang.String这个类并不是被这个ClientDefClassLoader加载,而是由bootstrap classloader进行加载,为什么会这样?实际上这就是双亲委托模式的原因,因为在任何自定义ClassLoader加载一个类之前,它都会先委托它的父亲ClassLoader进行加载,只有当父亲ClassLoader无法加载成功后,才会由自己加载,在上面这个例子里,因为java.lang.String是属于Java核心API的一个类,所以当使用ClientDefClassLoader加载它的时候,该ClassLoader会先委托他的父亲ClassLoader进行加载,上面说过,当ClassLoader的parent为null时,ClassLoader的parent就是bootstrap classloader,所以在ClassLoader的最顶层就是bootstrap classloader,因此最终委托到bootstrap classloader的时候,bootstrap classloader就会返回String的Class。

下面我们看一下ClassLoader中的一段源码:

public class Snippet{

protected synchronized Class loadClass(String name,boolean resolve) throws
    ClassNotFoundException{
    //首先检查该name指定的class是否被加载
    Class c = findLoadedClass(name);
    if(c==null){
        try{
            if(parent!=null){
            //如果parent不为null,则调用parent的loadClass进行加载
            c=parent.loadClass(name,false);
            }else{
            //如果parent为null,则调用BootstrapClassLoader进行加载
            c=findBootstrapClass0(name);
            }
   }catch(ClassNotFoundException e){
        //如果仍然无法加载成功,则调用自身的findClass进行加载
        c=findClass(name);
    }

}
if(resolve){resolveClass(c);}
return c;
}
}
从上面的一段代码,我们可以看出一个类加载的大概过程,与我们刚开始所举的例子是一样的,而我们要实现一个自定义类的时间,只需要实现findClass方法即可。

相关文章
|
3月前
|
Java 关系型数据库 MySQL
在Java的反射中,Class.forName和ClassLoader的区别
在Java的反射中,Class.forName和ClassLoader的区别
93 3
|
16天前
|
前端开发 Java 编译器
classpath中存在多个jar存在同限定名的class classloader会如何加载
总之,合理组织类路径和使用现代化的构建工具,可有效避免类加载冲突,保证应用的稳定运行。
31 8
|
1月前
|
安全 Java 数据库
使用`Class.forName`动态加载类
使用`Class.forName`动态加载类
|
3月前
|
Java
Class.forName和ClassLoader到底有啥区别
Class.forName和ClassLoader到底有啥区别
19 0
|
3月前
|
存储 缓存 前端开发
JVM(二):Class加载机制
JVM(二):Class加载机制
|
存储 安全 前端开发
jvm之.class文件解读(上)
jvm之.class文件解读(上)
|
安全 前端开发 Java
ClassLoader 加载| 学习笔记
快速学习 ClassLoader 加载
ClassLoader 加载| 学习笔记
|
Arthas Java 测试技术
class 和 classloader 相关命令:redefine | 学习笔记
快速学习 class 和 classloader 相关命令:redefine
248 0
class 和 classloader 相关命令:redefine | 学习笔记
|
Java
打印当前ClassLoader 加载了哪些Jar
打印当前ClassLoader 加载了哪些Jar
227 1
|
安全 前端开发 Java
ClassLoader加载|学习笔记
快速学习ClassLoader加载
ClassLoader加载|学习笔记