JAVA系列之类加载机制详解
作者:互联网
一、类加载 icode9 过程
程序员编写的Java源程序(.java文件)在经过编译器编译之后被转换成字节代码(.class 文件),类加载器将.class文件中的二进制数据读入到内存中,将其放在方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。
类加载的最终产品是位于堆区中的Class对象,Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口。
以下是举例说明类加载过程:
二、类生命周期
类的生命周期包括:加载、验证、准备、解析、初始化、使用、卸载7个阶段。其中加载、验证、准备、初始化、卸载5个阶段是按照这种顺序按部就班的开始,而解析阶段则不一定:某些情况下,可以在初始化之后再开始,这是为了支持Java语言的运行时绑定(也称为动态绑定或晚期绑定,其实就是多态),例如子类重写父类方法。
注意:这里写的是按部就班的开始,而不是按部就班地进行或完成,因为这些阶段通常都是互相交叉混合式进行的,通常会在一个阶段执行过程中调用、激活另外一个阶段。
1、icode9 加载
加载阶段会做3件事情:
-
通过一个类的全限定名来获取定义此类的二进制字节流。
-
将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
-
在Java堆中生成一个代表这个类的java.lang.Class对象,作为对方法区中这些数据的访问入口。
此处第一点并没指明要从哪里获取、怎样获取,因此这里给开发人员预留了扩展空间。许多Java技术就建立在此基础上,例如:
-
从ZIP包读取,如JAR、WAR。
-
从网络中获取,这种场景最典型应用场景应用就是Applet。
-
运行时计算生成,使用较多场景是动态代理技术,如spring icode9 AOP。
加载阶段完成后,虚拟机外部的二进制字节流就按照虚拟机所需的格式存储在方法区之中,而且在Java堆中也创建一个java.lang.Class类的对象,这样便可以通过该对象访问方法区中的这些数据。
2、验证
确保被加载的类的正确性,分为4个验证阶段:
-
文件格式验证
-
元数据验证
-
字节码验证
-
符号引用验证
验证阶段非常重要的,但不是必须的,它对程序运行期没有影响,如果所引用的类经过反复验证,那么可以考虑采用-Xverifynone参数来关闭大部分的类验证措施,以缩短虚拟机类加载的时间。
3、准备
为类的静态变量分配内存,并初始化默认值,icode9 这些内存是在方法区中分配,需要注意以下几点:
-
此处内存分配的变量仅包含类变量(static),而不包括实例变量,实例变量会随着对象实例化被分配在java堆中。
-
这里默认值是数据类型的默认值(如0、0L、null、false),而不是代码中被显示的赋予的值。
-
如果类字段的字段属性表中存在ConstatntValue属性,即同时被final和static修饰,那么在准备阶段变量value就会被初始化为ConstValue属性所指定的值。