首页 / JAVA / 理解 Java 中的类装载器
理解 Java 中的类装载器
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了理解 Java 中的类装载器,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含5592字,纯文字阅读大概需要8分钟。
内容图文
0. 类的生命周期
类装载器是 Java 中的一项创新,它使得 Java 虚拟机可以在执行的过程中再把一个 Java 类读入虚拟机,提高了程序的灵活性。在Java中,类的信息是被保存在方法区中的。在介绍类装载器之前,我们先了解一下 Java 中类的生命周期。Java 中一个类的生命周期可以划分为以下 6 个步骤:
- 装载,通过类加载器,把一个类的二进制读入到虚拟机中,并最终生成一个 Class 实例对象;
- 链接,把二进制数据合并到虚拟机的运行时状态中去,这一步又可以分为以下三个部分:
- 验证,确保二进制的格式正确;
- 准备,在方法区中为该类分配它所需要的内存;
- 解析,把常量池中的符号引用转化为值引用(这一步也可以在变量被使用到时再进行,即懒加载)
- 初始化:
- 如果该类的父类尚未初始化,则先初始化其父类;
- 如果该类存在一个初始化方法
<clinit>()
,则执行此方法(初始化方法由编译器生成,程序员不可手动在 Java 源代码中添加);
- 对象的创建,如果程序中发现如下关键字
new
,newInstance
,clone
,getObject
,则意味着需要在堆内存中创建一个对象,创建对象时会调用到<init>()
方法(对应类的构造方法),初始化方法执行前必须先调用父类的初始化方法; - 对象的终结,如果一个对象不再被引用,则会在垃圾收集程序执行时被垃圾收集器收集,一个对象在被垃圾收集程序收集的时候会显式的调用其
void finalize()
方法(如果定义了该方法的话); - 类的卸载,如果一个类不再使用,则也会被垃圾收集器收集。只有用户自定义的 ClassLoader 所装载的类才会被卸载,BootStrapClassLoader 所装载的类不会被卸载。
其中,以上的 1 ~ 3 步可以统称为类的初始化,类的初始化只可能在以下 5 种情况中发生(类初始化只会执行一次,如果类已经初始化了并且没有被卸载,则下次使用时不需要再进行初始化):
- 遇到
new
,getstatic
,putstatic
,invokestatic
关键字的时候; - 使用
java.lang.reflect
包对类进行反射调用的时候; - 当初始化一个类时,如果其父类尚未初始化,则会先初始化其父类;
- 当虚拟机启动时,包含
main()
方法的那个类会被初始化; - 当使用 JDK1.7 的动态语言支持时,如果一个
java.lang.invoke.MethodHandle
实例的最后解析结果是REF_getStatic
,REF_putStatic
,REF_invokeStatic
的方法句柄的时候;
1. 类加载器基本概念
这篇文章所要讨论的类装载器对应的是类的生命周期中的第一步:装载。
顾名思义,类装载器的作用就是把一个Java的字节码数据加载到JVM中,并且生成一个java.lang.Class
类的实例。每个这样的实例用来表示一个 Java 类,通过此实例的 newInstance()
方法就可以创建出该类的一个对象。
我们可以通过java.lang.ClassLoader
类来对一个字节码数据进行加载,该类主要包含以下和类加载相关的方法:
方法 | 说明 |
---|---|
getParent() | 返回该类加载器的父类加载器 |
loadClass(String name) | 加载名称为 name的类,返回的结果是 java.lang.Class类的实例 |
findClass(String name) | 查找名称为 name的类,返回的结果是 java.lang.Class类的实例 |
findLoadedClass(String name) | 查找名称为 name的已经被加载过的类,返回的结果是 java.lang.Class类的实例 |
defineClass(String name, byte[] b, int off, int len) | 把字节数组 b中的内容转换成 Java 类,返回的结果是 java.lang.Class类的实例。这个方法被声明为 final的 |
resolveClass(Class<?> c) | 链接指定的 Java 类 |
其中最核心的就是方法是defineClass
方法,它负责把一连串的字节码二进制数据转化为一个Class
类的实例,而不论的这些字节码来自于什么地方。
2. JVM提供的类加载器
系统类加载器是由 JVM 提供的、可以直接使用的类加载器,JVM中的系统类加载器有如下三个:
引导类加载器(bootstrap class loader):它用来加载 Java 的核心库,该加载器由C++实现,不继承自 java.lang.ClassLoader。它负责加载Java的基础类,主要是
%JRE_HOME/lib/
目录下的rt.jar
、resources.jar
、charsets.ja
r和class
等,如果想要使用引导类加载器来加载我们自己的jar包,可以使用如下的方式来实现我们可以在运行时使用如下参数: -Xbootclasspath:完全取代系统Java classpath.最好不用。 -Xbootclasspath/a: 在系统class加载后加载。一般用这个。 -Xbootclasspath/p: 在系统class加载前加载,注意使用,和系统类冲突就不好了. win32 java -Xbootclasspath/a: some.jar;some2.jar; -jar test.jar unix java -Xbootclasspath/a: some.jar:some2.jar: -jar test.jar win32系统每个jar用分号隔开,unix系统下用冒号隔开
- 扩展类加载器(extensions class loader):它用来加载 Java 的扩展库,主要是
%JRE_HOME/lib/ext
目录下的jar和class文件,你可以把需要加载的jar都扔到%JRE_HOME%/lib/ext
下面,这个目录下的jar包会在Bootstrap Classloader工作完后由Extension Classloader来加载。 - 系统类加载器(system class loader):它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的,可以通过
ClassLoader.getSystemClassLoader()
来获取它。如果想要让指定的jar被加载,只需要在MANIFEST.MF
中添加如下代码:Class-Path: lib/demo.jar lib/demo1.jar
,就可以把指定的jar添加到CLASSPATH中了。
其中,Bootstrap ClassLoader由JVM启动,然后初始化sun.misc.Launcher ,sun.misc.Launcher初始化Extension ClassLoader、App ClassLoader。除了Bootstrap ClassLoader,其余的类加载器本身也由其它的类加载器进行加载,所以某个类加载器的父类加载器就是加载了这个类加载器的那个加载器。在JVM提供的加载器中,系统类加载器的父类加载器是扩展类加载器,扩展类加载器的父类加载器是引导类加载器。
3. 自定义类加载器
如果JVM提供的类加载器无法满足我们的需求,那我们就需要实现自己的类加载器。
自定义类加载器十分简单,只需要通过调用ClassLoader
类的Class<?> java.lang.ClassLoader.defineClass(String name, byte[] b, int off, int len)
方法即可,不过由于该方法是final
并且protected
的,所以我们必须要继承ClassLoader
类并且使用super.xxx()
的格式来调用。下面是一个demo
1 | import java.io.File; |
内容总结
以上是互联网集市为您收集整理的理解 Java 中的类装载器全部内容,希望文章能够帮你解决理解 Java 中的类装载器所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。