类从装入到虚拟机的内存,并在其上卸载(整个程序\系统运行结束虚拟机构的闭合),其整个生命周期包括:装入、链接、初始化、使用、卸载。
由于此处重点讨论类的装入这个过程,因此不涉及类的使用和卸载,稍后将讨论默认类的装入这个过程,包括:加载、链接、初始化
加载此处称为加载,很容易让人误解,会觉得加载就是这里,实际上并不是这个样子,这里加载二字和类的装入不是一回事,可以这样理解,加载是类装入的一个阶段,这个阶段,虚拟机主要做三件事:

根据类的全路径来获得类的二进制字节流。
将对应此字节流的结构转换为方法区的运行时数据结构(将编码的组织方式转换为虚拟机运行时可以读取的结构,存放在方法区)
在内存中生成一个Class对象(java.lang.Class),将数据关联到该方法区中。
在此要特别指出的是,上述三点,仅仅是虚拟机规范所定义的,至于具体如何实现,取决于具体的虚拟机;例如,获取二进制流并不一定要从字节码文件(Class文件)开始,可以从ZIP开始,从网络开始,利用代理在计算过程中生成等等;
此外,还需要执行第三个操作,即生成的Class对象不一定位于堆区,例如,将Class对象放置在方法区的HostSpot虚拟机的实现。
链接连接阶段又细分为三个步骤:验证、准备、解析
验证
首先,它的职责是确保Class文件的字节流中包含的信息符合规定,而不会破坏虚拟机;事实上,说白了,它的主要责任在于保证您编写的代码符合Java语法,而且合理地可行。编译器拒绝,如果不合理。在文件格式验证、元数据验证、字节码验证等方面进行了验证,并对符号引用进行了验证;
验证文件格式是否符合Class文件格式,元数据的验证主要是通过语义语法来实现的,即验证是否符合Java语言规范,例如:一个类是否有父类(我们知道Java处理Obja,所有的类都应该有一个父类),字节码的验证主要是验证数据流和控制流,以确保程序语义合法、合逻辑,例如:在操作栈中先放入Int型的数据,然后在其他地方使用它时,再将其与验证符号引用是为了确保正确执行解析操作。
在整个验证过程中,保证了Java语言的安全,避免出现无法控制的情况。(补充一下,这里所说的验证,不可控性,包括上面提到的例子,并非我们在编程中写的a!
=null,这是对我们编写的程序下一层的字节码的解析),对于加载的过程来说,验证阶段很重要,但不必一定要这样做,因为它对程序运行期间没有任何影响,只是为了保证语言的安全性,如果运行的所有代码都经过了反复的使用和验证,那么在执行阶段,可以考虑使用-Xlify:none参数来关闭大多数验证过程,从而缩短虚拟机加载的时间。
准备
预备阶段的主要作用是正式地为类变量分配内存和设置类变量的初值,也就是这些变量使用的内存都是在方法区中分配的。此处需要注意的是,此时只有一个类变量在分配内存,也就是说,静态变量(static修饰的),而没有包括实例变量,实例变量将在实例化时分配在堆内存中,初始值也不是我们能赋值的。
例如:
public Class A{ public String name; public static int value = 987;}1234567复制代码类型:[java]
正如刚才所说,这里在准备阶段,只为vala变量分配内存,而不为name;在准备阶段,为vala分配完内存,同时为其赋值,但不为其赋值987,在准备阶段,vala的值为0。而且,赋值为987的指令,在程序被编译之后,存放在类构造器()方法中。
解析
解析阶段的任务是用直接引用替换常量池中的符号引用。
可将常量池理解为存储代码符号的地方,比如在代码中声明的变量,它只是一个符号,没有实际内存,而所有这些符号都将被放置在常量池中。举例来说,一个类的方法是tyle(),那么符号引用就是tyle,该方法在内存中存在的地址假定是0x123456,那么该地址就是直接引用。
标记引用:
systemreferences更多的是用一组符号来描述被引用的内存目标,systemreferences与内存空间实际上没有任何关系,引用的目标不一定在内存中,只是当我们在代码中自己编写时加以区分,比如一个systemreferences,one就是一个'o','n','e'三个符号的组合,它什么都不是。
直接参考:
直指存储器空间的指针、相对便宜的存储器容量或能够简明扼要地定位到存储器目标的句柄都可以被直接引用。
分析操作主要是对类的引用,接口,字段,类方法,方法类型,方法句柄和调用点限定符号。
初始化(Initialize)加载、连接完全由虚拟机支配和控制,而在类的加载过程中,到了初始化阶段,真正开始执行在类中定义的Java代码。初始化实际上是我个人理解的,它是指为类的类变量初始化值,在准备阶段变量已经进入一次赋值,只不过这是系统需要的初始值,而在初始化阶段赋值,这是主观程序,由开发人员根据主观程序去初始化变量和其他资源。这一步骤的初始化方法有两种类型:
1、在声明类变量时,直接给变量赋值
2、在静态初始化块为类变量赋值
使用
就是对象之间的调用通信等等
卸载(死亡)
遇到如下几种情况,即类结束生命周期:
执行了System.exit()方法
程序正常执行结束
程序在执行过程中遇到了异常或错误而异常终止
由于操作系统出现错误而导致Java虚拟机进程终止