Java基础篇(JVM)——类加载机制

这是Java基础篇(JVM)的第二篇文章,紧接着上一篇字节码详解,这篇我们来详解Java的类加载机制,也就是如何把字节码代表的类信息加载进入内存中。

我们知道,不管是根据类新建对象,还是直接使用类变量/方法,都需要在类信息已经加载进入内存的前提下。在Java虚拟机规范中,类加载过程也就是类的生命周期包括7个部分:加载、验证、准备、解析、初始化、使用、卸载。不过我们先不写这几个阶段,先讲讲类加载器的知识,然后再来看具体的类加载过程。

1. 类加载器

关于类加载器,我主要关注两个方面,一是类加载器的作用,二是类加载器的双亲委托机制。

首先说第一个,类加载器在Java体系中有两个作用:

(1)在类生命周期的加载阶段,通过一个类的全限定名来获取此类的二进制字节流。在JVM规范中,没有强制规定类加载器为虚拟机的一部分,也就是说,类加载过程是可以放到JVM外部去实现的。说通俗一点,就是我们可以根据规范自己去实现加载器,如HotSpot实现中,启动类加载器是C++写的,是虚拟机的一部分,但其它类加载器都是Java写的,继承自java.lang.ClassLoader类。

这样规定有两个好处,一是二进制字节流的来源可以不限于Class文件,可从zip包获取(jar、war)、从网络获取(Applet)、运行时计算生成(动态代理)、从其它文件生成(JSP编译得到)等;第二个是我们可以自己实现类加载器,如OSGi就充分利用了类加载器的灵活实现(反双亲委托)、Tomcat等服务器也有自己的类加载器体系。

(2)在类的整个生命周期内,用来判定两个类是否相等。只有当类的全限定相等,且由同一个类加载器加载时,才认为两个类完全相等。这会影响到equals()方法、isAssignableFrom()方法、isInstance()方法(instanceOf)的执行结果。

这里我要问两个问题,一是普通类是和类加载器类相关联还是和它的实例相关联?二是它们是如何关联起来的?

第一个问题,应该是和类加载器的实例相关联。从需求出发,我们需要有多个不同的类加载器来加载类,这时候就不能使用静态的方法,而应用实例来加载;而且从结果来推过程:看ClassLoader等的源码,loadClass()方法都不是static的,所以应该是和类加载器的实例相关联。

第二个问题,我们看到ClassLoader类中维护了一个HashSet,这个集合中存储的是以该加载器作为初始加载器的类的全限定名,这称为类加载器的命名空间,这样,类和类加载器就联系起来了。

对Java程序员来说,类加载器的体系结构如图:

![](https://img2018.cnblogs.com/blog/1252920/201810/1252920-20181015174708717-891192826.png)

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zydyjz.html