一个类型从被加载到虚拟机内存中开始,到卸载出内存结束总共经历了七个阶段。分别是加载-验证-准备-解析-初始化-使用-卸载。其中验证,准备和解析都被统称为连接阶段。
当一个类在初始化时,要求其父类必须全部完成初始化,但是接口在初始化时并不要求其父接口全部完成初始化。
加载
1)通过一个类的全限定类名来获取定义此类的二进制字节流
2)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
3)在内存中生成一个代表这个类的Class对象,作为方法区这个类的各数据入口
验证
1)文件格式验证,验证字节流是否符合Class文件格式的规范
2)元数据验证,对字节码描述的信息进行语法分析,保证其描述的信息符合《Java语言规范》
3)字节码验证,通过对数据流分析和控制流分析,来确保语义是合法的符合逻辑的,同时保证方法运行不会恶意危害虚拟机安全
准备
准备阶段就是正式为类中定义的静态变量分配内存并设置初始值的阶段。不包括实例变量,实例变量会在对象实例化时随对象一起分配在堆中。初始值一般来说是该数据类型的零值。
解析
解析阶段就是Java虚拟机将常量池中使用的符号引用转换为直接引用的过程。
符号引用:用一组符号来单纯的描述所代表的的目标,符号可以是任何形式的字面量,只要可以无歧义的定位到目标即可。
直接引用:是可以直接指向目标的指针,相对偏移量或者是一个可以间接定位到目标的句柄。
初始化
初始化就是执行类构造器方法的过程。方法就是编译器自动收集类中的所有类变量的赋值动作和静态代码块,并按语句在源文件中出现的顺序来执行。
类加载器
引导类加载器(BootStrapClassLoad)
1)这个类加载器在JVM的内部,使用C/C++语言实现
2)它用来加载Java的核心库(JAVA
_HOME/jre/lib/rt.jar或sun.boot.class.paht路径下的内容),用于提供JVM自身所需要的类
3)为扩展类加载器和系统类加载的父类加载器(双亲委派)
扩展类加载器
1)Java语言编写
2)派生于ClassLoad类
3)父加载器为引导类加载器
4)从jre/lib/ext的子目录下加载类库
系统类加载器
1)Java语言编写
2)派生于ClassLoad类
3)父加载器为扩展类加载器
4)该类加载器是程序中的默认加载器一般来说Java应用程序的类都是由它来加载
自定义类加载器
在Java的日常应用程序开发中,类的加载都是由以上三种加载器完成加载的,但是在必要时我们还可以自定义类加载器来制定类的加载方式。
1)隔离加载类
2)扩展加载页
3)防止源码泄露
用户自定义类加载器方法
1)开发人员可以通过继承抽象类java.lang.ClassLoad类的方式实现自定义类加载满足特定需求
2)如果没有太复杂的需求,可以直接继承URLClassLoad类,这样可以避免自己去编写findClass方法以及其获取字节流的方法。
双亲委派机制
工作过程:如果一个类加载器收到了加载类的请求,它首先不会自己来尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都传递到了最顶层的引导类加载器,只有当父类加载器反馈自己无法完成这个加载请求时(它的搜索范围中没有发现这个类),子加载器才会尝试自己去完成这个加载请求。
优势:
1)可以避免类的重复加载来提升效率
2)保护程序安全,防止JDK的核心API被篡改