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方法即可。

相关文章
|
6月前
|
并行计算 Ubuntu Docker
kTransformers DeepSeek R1 部署全流程指南
kTransformers DeepSeek R1 部署全流程指南
|
缓存 负载均衡 监控
探秘数据库中间件:ProxySQL与MaxScale的优势与劣势
探秘数据库中间件:ProxySQL与MaxScale的优势与劣势
644 2
|
机器学习/深度学习 自动驾驶 算法
基于深度学习的图像识别在自动驾驶车辆中的应用
【5月更文挑战第5天】 随着人工智能技术的飞速发展,特别是深度学习在图像处理领域的突破性进展,自动驾驶汽车得以利用这些先进技术实现对环境的高效识别和理解。本文将探讨如何通过深度学习模型优化自动驾驶系统中的图像识别过程,以及这一技术如何提升车辆的安全性与可靠性。我们将重点讨论卷积神经网络(CNN)在道路标识、行人检测和障碍物分类中的应用,并通过实例展示深度学习算法在真实世界数据上的性能表现。
|
人工智能
人工智能伦理:我们如何确保AI的发展不会失控?
随着人工智能技术的飞速发展,其在各行各业的应用也日益广泛。然而,随之而来的伦理问题也日益凸显。本文将探讨人工智能伦理的重要性,以及我们如何通过制定规范和标准,确保AI的发展不会失控。
279 0
|
弹性计算 监控 JavaScript
云服务器 ECS产品使用问题之Node.js项目部署成功后无法通过公网IP+端口号访问,是什么导致的
云服务器ECS(Elastic Compute Service)是各大云服务商阿里云提供的一种基础云计算服务,它允许用户租用云端计算资源来部署和运行各种应用程序。以下是一个关于如何使用ECS产品的综合指南。
|
存储 算法 Go
这么简单的问题都不会,那还面试什么!?
gozero如何自定义goctl?本文详解和实战,通过本文你将了解goctl的妙用,提高你的开发效率。介绍如何使用goctl工具实现模板定制化,并根据实际项目业务需求进行模板定制化实现。
这么简单的问题都不会,那还面试什么!?
|
Oracle 关系型数据库 MySQL
windows安装ODBC
windows安装ODBC
141 0
|
缓存 前端开发 JavaScript
前端面试的性能优化部分(12)每天10个小知识点
前端面试的性能优化部分(12)每天10个小知识点
109 0
|
NoSQL 前端开发 PHP
thinkphp+redis实现秒杀功能
thinkphp+redis实现秒杀功能
335 0
thinkphp+redis实现秒杀功能
|
Java 程序员
JAVA人事管理系统
JAVA人事管理系统
163 0