类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。类的加载的最终产品是位于堆区中的Class对象,Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口。
加载.class文件的方式
-从本地系统中直接加载
-通过网络下载.class文件
-从zip,jar等归档文件中加载.class文件
-从专有数据库中提取.class文件
-将JAVA源文件动态编译为.class文件
流程1:加载
做了三件事:
第一件:通过一个类的权限定名来获取其定义的二进制字节流。
第二件:将这个字节流锁代表的静态存储结构转化为方法区运行时数据结构
第三件:在JAVA堆中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
流程2:连接
验证:确保被加载类的正确性
准备:为类的静态变量分配内存
解析:把类中的符号引用转换为直接引用
流程3:初始化
为类的静态变量赋予正确的初始值,JVM负责对类进行初始化,主要对变量进行初始化。
1.如果这个类还没有被加载和连接,则程序先加载并连接该类
2.如果该类的直接父类还没有被初始化,则先初始化其直接父类。
3.如果类中有初始化语句,则系统依次执行这些初始化语句。
类加载器
注意这里的父类加载器并不是通过集成实现的,而是通过组合实现的。
启动类加载器:Bootstrap ClassLoader 负责加载存放在Jre/lib下的jar或java文件,如rt.jar
扩展类加载器:Extension ClassLoader 负责加载jre/lib/ext目录中的所有类库。
应用类加载器:Application ClassLoader,负责加载用户类路径所指定的类。
上述三类加载器相互配合进行加载的,如果有必要可以自己加入自定义的加载器。
JVM加载机制
全盘负责:当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他CLass也将由该类加载器负责载入,除非显示使用另一个类加载器来载入。
父类委托:先让父类加载器视图加载该类,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类
缓存机制:缓存机制将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区寻找该CLass,只有缓存区不存在,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓存区。
类的加载
类的加载有三种方式
方式1:命令行启动应用时候由JVM初始化加载
方式2:通过CLass.forName()方法动态加载
方式3:通过CLassLoader.loadClass方法动态加载
Class.forName()和ClassLoader.loadClass()区别
Class.forName():将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static块;
ClassLoader.loadClass():只干一件事情,就是将.class文件加载到jvm中,不会执行static中的内容,只有在newInstance才会去执行static块。
5、双亲委派模型
双亲委派模型的工作流程是:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把请求委托给父加载器去完成,依次向上,因此,所有的类加载请求最终都应该被传递到顶层的启动类加载器中,只有当父加载器在它的搜索范围中没有找到所需的类时,即无法完成该加载,子加载器才会尝试自己去加载该类。
双亲委派机制:
1、当AppClassLoader加载一个class时,它首先不会自己去尝试加载这个类,而是把类加载请求委派给父类加载器ExtClassLoader去完成。
2、当ExtClassLoader加载一个class时,它首先也不会自己去尝试加载这个类,而是把类加载请求委派给BootStrapClassLoader去完成。
3、如果BootStrapClassLoader加载失败(例如在$JAVA_HOME/jre/lib里未查找到该class),会使用ExtClassLoader来尝试加载;
4、若ExtClassLoader也加载失败,则会使用AppClassLoader来加载,如果AppClassLoader也加载失败,则会报出异常ClassNotFoundException。
双亲委派模型意义:
-保证Java程序安全稳定运行