在之前的文章里分享过JVM的内存模型、栈帧等知识点,本篇聊下基础内容,java代码的加载过程和类加载器。
java加载过程
- 编译:首先.java文件会编译成字节码.class文件.
- 加载:会通过类加载器加载到JVM内存中,其中classloader有四种:bootstrap类加载器(根类加载)、extension类加载器(扩展类加载器)、application类加载器(应用程序类加载器)、custom自定义加载器。
- 链接:链接过程主要分三部分: 验证:字节码校验器会检查生成的字节码是否正确,如果错误就会链接失败, 准备:对于所有静态变量的内存分配和默认值分配 ,识别:从运行时常量池的符号应用中动态的赋值的过程。
- 初始化:静态变量赋值为初始值,静态代码块将被执行。
类加载器
通过上边代码加载的过程,我们会发现我们会用到类加载器,而java中的类加载器,通常采用的是双亲委派模型,接下来重点介绍下java中的类加载器。
概念澄清
我们都知道,Java中采用的是双亲委派模型,这里的双亲不是只的类的继承关系,重要的事情说三遍,类加载器不是java语法中的类的继承(不是extends),类加载器不是java语法中的类的继承(不是extends)、类加载器不是java语法中的类的继承(不是extends)。
各类加载器java代码实现
首先顶级的父类 public abstract class ClassLoader
bootstrap类加载器:本身是jvm内部 用c++写的一个模块,在Java中是没有一个这样的类跟他对应的。
ext类加载器:class ExtClassLoader extends URLClassLoader
application 类加载器:AppClassLoader extends URLClassLoader
自定义类加载器:这个是自己定义的,所以可以直接继承ClassLoader
双亲委派的执行过程
我们以A.class文件为例来看下双亲委派的加载过程:
具体过程如上图,我们来分析下过程:
一、自底向上检查类是否已经加载过:
首先custom类加载器检查A是否已经被自己加载过,如果存在正常返回,不存在会委托给他的父加载器app类加载器,如果app类加载器检查不存在,会委托他的父加载器ext类加载器,如果ext类加载器不存在会委托给bootstrap类加载器检查是否已经加载过A这个类。
二、自顶向下进行实际的查找和加载:
如果bootstrap类加载器没找到A,那么会委派ext类加载器去查找类并加载、如果ext没有找到会指派app类加载器去查找和加载、如果app类加载器没有找到和加载会指派给coustom去查找和加载,如果还没找到会抛出class not fund exception.
在这个过程中只要任何一个找到了或加载了类A就会直接返回。