超级详细的 Java 类加载器学习总结
上一篇,我们详细讲解了java类的加载机制,本篇我们继续讲解java类加载器的内容。
本文学习目录:
什么是类加载器? 类加载器的树状层次结构 类加载器的工作原理 双亲委派模型 类加载的过程 一、 什么是类加载器?
类加载器(class loader)用来加载 Java 类到 Java 虚拟机中。一般来说,Java 类的虚拟机使用 Java 方式如下:Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成 java.lang.Class类的一个实例。每个这样的实例用来表示一个 Java 类。通过此实例的 newInstance()方法就可以创建出该类的一个对象。实际的情况可能更加复杂,比如 Java 字节代码可能是通过工具动态生成的,也可能是通过网络下载的。
二、类加载器的树状层次结构
Java 中的类加载器大致可以分成两类,一类是系统提供的,另外一类则是由 Java 应用开发人员编写的。
类加载器的树状层次结构图
1.引导类加载器(bootstrap class loader):
它用来加载 Java 的核心库(jre/lib/rt.jar),是用原生C++代码来实现的,并不继承自java.lang.ClassLoader。加载扩展类和应用程序类加载器,并指定他们的父类加载器,在java中获取不到。
2.扩展类加载器(extensions class loader):
它用来加载 Java 的扩展库(jre/ext/*.jar)。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。
3.系统类加载器(system class loader):
它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader()来获取它。
4.自定义类加载器(custom class loader):
除了系统提供的类加载器以外,开发人员可以通过继承 java.lang.ClassLoader类的方式实现自己的类加载器,以满足一些特殊的需求。
测试代码案例:
输出结果:
测试案例可以看出ClassLoader类是由AppClassLoader加载的。他的父亲是ExtClassLoader,ExtClassLoader的父亲无法获取是因为它是用C++实现的。
三、类加载器的工作机制
虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。
类加载器就是寻找类的字节码文件并构造出类在JVM内部表示的对象组件。在java中,类加载器把一个类装入JVM中,要经过以下步骤:
1.装载:查找和导入Class文件;
2.链接:执行校验、准备和解析步骤,其中解析步骤是可以选择的;
(1)校验:检查载入Class文件数据的正确性;
(2)准备:给累的静态变量分配存储空间;
(3)解析:将符号引用转成直接引用;
3.初始化:对类的静态变量、静态代码块执行初始化工作。
类加载工作由ClassLoader及其子类负责,ClassLoader是一个重要的java运行时系统组件,他负责在运行时查找和装入Class字节码文件。JVM在运行时会产生三个ClassLoader:根装载器、扩展类加载器和应用程序类加载器。其中根装载器不是ClassLoader的子类,它是由C++语言编写,因此我们在java中看不到它。根装载器负责装载JRE的核心类库,如JRE目标下的大rt.jar、charsets.jar等。扩展类加载器和应用程序类加载器都是ClassLoader的子类,其中扩展类加载器负责装载JRE扩展目录ext中的JAR类包;应用程序类加载器负责加载Classpath路径下的类包。
四、双亲委派模型
双亲委派模型过程
某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。
使用双亲委派模型的好处在于Java类随着它的类加载器一起具备了一种带有优先级的层次关系。例如类java.lang.Object,它存在在rt.jar中,无论哪一个类加载器要加载这个类,最终都是委派给处于模型最顶端的Bootstrap ClassLoader进行加载,因此Object类在程序的各种类加载器环境中都是同一个类。相反,如果没有双亲委派模型而是由各个类加载器自行加载的话,如果用户编写了一个java.lang.Object的同名类并放在ClassPath中,那系统中将会出现多个不同的Object类,程序将混乱。因此,如果开发者尝试编写一个与rt.jar类库中重名的Java类,可以正常编译,但是永远无法被加载运行。
双亲委派模型的系统实现
在java.lang.ClassLoader的loadClass()方法中,先检查是否已经被加载过,若没有加载则调用父类加载器的loadClass()方法,若父加载器为空则默认使用启动类加载器作为父加载器。如果父加载失败,则抛出ClassNotFoundException异常后,再调用自己的findClass()方法进行加载。
五、类加载器的过程
首先我们先看一下类加载器过程图,如下:
java类加载器过程图
类加载器的过程包括了三个大步骤,他们分别是:
加载
1.加载指的是将类的class文件读入到内存,并为之创建一个java.lang.Class对象。
2.通过类的全限定名获取此类的二进制字节流。
3.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
4.在内存中生成一个Class对象,作为方法区这个类的各种数据的访问入口。
加载通常由类加载器完成,加载类的方式具体有以下几项:
1.本地资源加载。
2.网络加载。Web Applet。
3.zip压缩包加载。jar,war。
4.运行时计算生成。动态代理技术。
5.其他文件生成。JSP应用。
6.从加密文件中读取,主要是为了防止class文件被反编译。
链接
链接分为三个步骤:
1.验证
确保class文件的字节流中包含信息符合虚拟机要求。
主要包括,文件格式验证,元数据验证,字节码验证,符号引用验证。
2.准备
为类变量分配内存,并为变量赋零值。
这里不包括用final修饰的static,因为final在变异的时候就会分配了,准备阶段会显式初始化。不会为实例变量分配初始化。
3.解析
将常量池内的符号引用变为直接引用。
初始化
初始化阶段就是执行类构造器方法()方法。
()方法是由javac将类变量赋值动作和静态代码块中的语句合并自动产生的。当类不存在类变量和静态代码块时不会自动生成此方法。一个类只会被加载一次,()方法是同步加锁的。
总结了这么多,你学会了吗?
上一篇: java 遗传记忆图(简单易懂)
推荐阅读
-
[PyTorch 与深度学习] 4、PyTorch 的数据集和数据加载器详细使用教程
-
jvm 的 java 类加载机制和类加载器(ClassLoader)的详细信息
-
Java 的类加载器(ClassLoader)简介
-
通俗易懂的 JAVA 类加载器
-
jvm 的 java 类加载机制和类加载器(ClassLoader)的详细信息
-
jvm 的 java 类加载机制和类加载器(ClassLoader)的详细信息
-
Java 类加载器的作用 - 简介:类加载器是 Java™ 中一个非常重要的概念。类加载器负责将 Java 类的字节码加载到 Java 虚拟机中。本文首先详细介绍了 Java 类加载器的基本概念,包括代理模型、加载类的具体过程和线程上下文类加载器等。然后介绍了如何开发自己的类加载器,最后介绍了类加载器在 Web 容器和 OSGi™ 中的应用。 类加载器是 Java 语言的一项创新,也是 Java 语言广受欢迎的重要原因之一。它允许将 Java 类动态加载到 Java 虚拟机中并执行。类加载器从 JDK 1.0 开始出现,最初是为了满足 Java Applets 的需求而开发的,Java Applets 需要从远程位置下载 Java 类文件并在浏览器中执行。现在,类加载器已广泛应用于网络容器和 OSGi。一般来说,Java 应用程序的开发人员不需要直接与类加载器交互;Java 虚拟机的默认行为足以应对大多数情况。但是,如果遇到需要与类加载器交互的情况,而您又不太了解类加载器的机制,就很容易花费大量时间调试异常,如 ClassNotFoundException 和 NoClassDefFoundError。本文将详细介绍 Java 的类加载器,帮助读者深入理解 Java 语言中的这一重要概念。下面先介绍一些基本概念。 类加载器的基本概念 顾名思义,类加载器用于将 Java 类加载到 Java 虚拟机中。一般来说,Java 虚拟机以如下方式使用 Java 类:Java 源程序(.java 文件)经 Java 编译器编译后转换为 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码并将其转换为 java.lang 实例。每个实例都用来表示一个 Java 类。通过该实例的 newInstance 方法创建该类的对象。实际情况可能更加复杂,例如,Java 字节代码可能是由工具动态生成或通过网络下载的。 基本上,所有类加载器都是 java.lang.ClassLoader 类的实例。下面将详细介绍这个 Java 类。 java.lang.ClassLoader 类简介 java.lang.ClassLoader 类的基本职责是根据给定类的名称为其查找或生成相应的字节码,然后根据这些字节码定义一个 Java 类,即 java.lang.Class 类的实例。除此之外,ClassLoader 还负责加载 Java 应用程序所需的资源,如图像文件和配置文件。不过,本文只讨论它加载类的功能。为了履行加载类的职责,ClassLoader 提供了许多方法,其中比较重要的方法如表 1 所示。下文将详细介绍这些方法。 表 1.与加载类相关的 ClassLoader 方法
-
类加载机制系列 1 - 深入了解 Java 中的类加载器
-
Java 类加载器 - 类加载器的原理和应用
-
JAVA 类加载器的分类 JAVA 类加载器的用途是什么?