1.类加载的时机
1.类加载的顺序
类从被加载到虚拟机内存中开始,到被卸载出内存为止,整个生命周期包括:加载(Loading),验证(verification),准备(preparation),解析(Resolution),初始化(Initialization)
,使用(Using)和卸载(Unloading)7个阶段。其中验证,准备,解析3个阶段统称为链接(Linking)。
图中加载,验证,准备,初始化,卸载5个阶段的顺序是固定的,类的加载过程必须按照这个顺序按部就班的开始,解析阶段不一定(解析阶段在某些情况下可以在初始化阶段之后再开始,这是为了支持Java语言的运行时绑定,也称为动态绑定或晚期绑定)。按部就班的“开始”,而非“进行”或者“完成”,是因为这些阶段通常都是互相交叉混合式进行,通常会在一个阶段执行过程中调用,激活另外一个阶段。
2. 5种必须初始化的情况
类何时执行第一个阶段:加载?Java虚拟机并没有进行强制约束,可以交给虚拟机的具体实现自由把握。但是对于初始化阶段,虚拟机规范则严格规定了有且只有5种情况必须立即对类进行“初始化”。
1.遇到new,putstatic,getstatic,invokestatic这4条字节码指令时,如果类没有进行初始化,则需要先触发初始化。
2.使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发初始化。
3.当初始化一个类的时候,如果发现其父类还没有初始化,则需要先触发父类的初始化。
4.当虚拟机启动时,用户需要指定一个要执行的主类(包含main方法的类),虚拟机会先初始化这个主类。
5.当jdk>1.7,使用jdk的动态语言支持时,如果一个Java.lang.invoke.MethodHandle实例最后的解析结果REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且这个方法句柄对应的类没有进行过初始化,则需要先触发其初始化。
对于这5种触发类进行初始化的场景,虚拟机规范种使用了一个很强烈的限定语:有且仅有,这5种场景的行为称为对一个类进行主动引用。其他引用类的方式都不会触发初始化,称为被动引用。
3.加载
在加载阶段虚拟机主要完成一下3件事情:
1.通过一个类的全限定名来获取定义此类的二进制字节流。
虚拟机没有指明二进制字节流要从一个class文件中获取,准确的说并没有规定从何处获取、怎么获取。所以扩展性很强,比如:
1.从zip包中读取,最终成为JAR、EAR、WAR格式的基础。
2.从网络中获取,这种场景最典型的应用是Applet。
3.运行时计算生产,这种场景使用得最多的就是动态代理技术,在java.lang.reflect.Proxy中,就是用了ProxyGenerator.generateProxyClass来为特定的接口生产形式为“$Proxy”的代理类的二进制字节流。
4.由其他文件生成,典型场景是JSP应用,有jsp文件生成对应的class类。
5.从数据库读取,场景较少,例如SAP Netweaver