类加载,指的是java进程运行的时候,需要把.class文件从硬盘,读取到内存,并进行一系列的校验解析的过程。(.class文件 => 类对象,硬盘 => 内存)
类加载的过程,类加载的过程其实是在java官方文档中给出的说明(Java 官方文档)
1. 类加载的过程(可以分为五个步骤)
1. 加载:把硬盘上的.class文件,找到打开文件,读取到文件内容(认为读到的是二进制的数据)
2. 验证:当前需要确保读到的文件的内容,是合法的.class文件(字节码文件)格式。(具体的验证依据,在Java的虚拟机规范中,有明确的格式说明)。
3. 准备:给类对象,申请内存空间。(此时申请到的内存空间,里面的默认值,都是全是0的。这个阶段中,类对象里的静态成员变量的值也就相当于是0了)。
4. 解析:主要是针对类中的字符串常量进行处理。(解析阶段是Java虚拟机常量池内的符号引用替换为直接引用的过程,也就是初始化常量的过程。)
5. 初始化:针对类对象完成后续的初始化 。(还要执行静态的代码块的逻辑,还可能会触发父类的加载)
2. 双亲委派模型
简单来说,描述了如何查找.class文件的策略。JVM中进行类加载的操作,是有一个专门的模块,称为“类加载器”(ClassLoader),JVM中的类加器默认是有三个。(也可以自定义的)
1. BootstrapClassLoader: 负责查找标准库的目录。
2. ExtensionClassLoader:负责查找扩展库的目录。
3. ApplicationClassLoader:负责查找当前项目的代码目录,以及第三方库的目录。
小结:上述的三个类加载器,存在“父子关系”(不是 面向对象中的,父类 子类继承关系,而是类似于“二叉树”,有一个指针(引用)parent,指向自己的“父”类加载器)
双亲委派模型工作过程:
1. 从ApplicationClassLoader作为入口,先开始工作。
2. ApplicationClassLoader 不会立即搜索自己负责的目录,会把搜索的任务交给自己的父亲。
3. 代码就进入到ExtensionClassLoader范畴了,ExtensionClassLoader也不会立即搜索自己负责的目录也要把搜素的任务交给自己的父亲。
4. 代码就进入到BootstrapClassLoader范畴了,BootstrapClassLoader也不想立即搜索自己负责的目录,也要把搜索的任务交给自己的父亲。
5. BootstrapClassLoader发现自己没有父亲,才会真正搜索负责的目录(标准库目录)通过全限定类名,尝试在标准库目录中找到符合要求的.class文件。如果找到了,接下来就直接进入到打开文件/读取文件等流程中。如果没找到,回到孩子这一辈的类加载器中,继续尝试加载。
6. ExtensionClassLoader收到父亲交给回他的任务之后,自己进行搜索负责目录(扩展库的目录)。如果找到了,接下来就直接进入到打开文件/读取文件等流程中。如果没找到,回到孩子这一辈的类加载器中,继续尝试加载。
7. ApplicationClassLoader 收到父亲交回给他的任务之后,自己进行搜索负责的目录(当前项目目录/第三方库目录)如果找到了,接下来就直接进入到打开文件/读取文件等流程中。如果没找到,回到孩子这一辈的类加载器中,继续尝试加载。由于默认情况下ApplicationClassLoader没有孩子了,此时说明类加载过程失败了!就会抛出ClassNotFoundExeception异常。