类的生命周期
在JAVA中数据类型分为基本数据类型和引用数据类型。基本数据类型,由虚拟机预先定义,引用数据类型则需要进行类加载。
JAVA将引用数据类型分为:类、接口、数组和泛型参数,而「泛型参数」在编译时期会被擦除, 因此JAVA虚拟机的类型实际上只有三种。「数组」是由JAVA虚拟机直接生成的;类、接口则有对应的「字节流」,这此不同形式的「字节流」都会被加载到JAVA虚拟机中。
按照JVM规范,从.CLASS文件到加载到内存中,到类的卸载出内存为止,它的整个生命周期包括7个阶段:
(1)“加载、验证、准备、初始化和卸载” 这五个阶段的顺序是确定的,“解析”可以在初始化之后再开始(运行时绑定或动态绑定或晚期绑定)。
(2)“验证、准备和解析”这三个阶段统称为连接(Linking)。
(2) 类加载过程分为:加载、验证、准备、解析和初始化五个阶段。
类加载过程
类加载过程分为:加载、验证、准备、解析和初始化五个阶段。这里的「加载」是指「类加载过程」的第一个阶段,在加载阶段,虚拟机需要完成以下 3 件事:
(1)通过一个类的全限定名来获取定义此类的二进制字节流, 使用的就是双亲委派机制;
(2)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构;
(3)在内存中生成一个代表这个类的 java.lang.Class 对象,作为方法区这个类的各种数据的访问入口。
类生命周期的其他阶段,不在该博文中介绍…
双亲委派机制是什么
类加载器查找CLASS所采用的是双亲委托模式,由向上委派和向下委派组成了双亲委派。
所谓双亲委托模式就是:首先判断该CLASS是否已经加载,如果没有被加载,不是自身去查找而是委托给父加载器进行查找,然后样依次进行递归,直到委托到最顶层的Bootstrap ClassLoader,如果Bootstrap ClassLoader找到了该CLASS,则直接返回,如果没找到,则继续依次向下查找,最后会交由自身去查找。
双亲委托机制的加载流程
(1)如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成。
(2)每一个层次的类加载器都是按照(1)进行递归,所以所有的加载请求最终都应该传送到顶层的启动类加载器中。
(3)只有当父加载器反馈自己无法完成这个加载请求时(搜索范围中没有找到所需的类),子加载器才会尝试自己去加载,如果子类也无法完成,则会依次往下传递,直到这个请求被成功加载,但是一直到自定义加载器都没有找到,JVM就会抛出ClassNotFund的异常。
一句话:先从下到上,再从上到下(或者说:向上委派,向下加载)
双亲委派机制的优点
简言之:保证类的唯一性和安全性
(1)避免类的重复加载
如果一个CLASS已经加载过了,就不会再次被加载,而是先从缓存中直接读取;
(2)保护程序安全
防止核心API被随意篡改。通过委托方式不会去篡改核心.CLASS,即使篡改也不会去加载,即使加载了也不再是同一个.CLASS对象了。不同的加载器加载同一个.CLASS也不是同一个CLASS对象。当自己程序中定义了一个和Java.lang包同名的类,因为使用的是双亲委派机制,会由启动类加载器去加载JAVA_HOME/lib中的类,而不是加载用户自定义的类。所以程序可以正常编译,但是自己定义的类无法被加载运行。