
虚拟机的类加载机制:虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型。
类型的加载、连接和初始化过程都是在程序运行期间完成的。
缺点:
令类加载时稍微增加一些性能开销
优点:
为Java应用程序提供高度的灵活性。
Java里天生可以动态扩展的语言特性就是依赖运行期动态加载和动态连接这个特点实现的。
第一,后文中直接对“类”的描述都包括了类和接口的可能性,而对于类和接口需要分开描述的场景会特别指明;
第二,本章所提到的“Class文件”并非特指某个存在于具体磁盘中的文件,这里所说的“Class文件”应当是一串二进制的字节流,无论以何种形式存在都可以。
类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括(5个阶段):
① 加载(Loading)
② 连接(Linking)
[1] 验证(Verification)
[2] 准备(Preparation)
[3] 解析(Resolution)
③ 初始化(Initialization)
④ 使用(Using)
⑤ 卸载(Unloading)
类的生命周期
加载、验证、准备、初始化和卸载这5个阶段的顺序是确定的,类的加载过程必须按照这种顺序按部就班地开始。而解析阶段则不一定:它在某些情况下可以在初始化阶段之后再开始,这是为了支持Java语言的运行时绑定(也称为动态绑定或晚期绑定)。
注意,这里说的是按部就班地“开始”,而不是按部就班地“进行”或“完成”,强调这点是因为这些阶段通常都是互相交叉地混合式进行的,通常会在一个阶段执行的过程中调用、激活另外一个阶段。比如,加载阶段与连接阶段的部分内容(如一部分字节码文件格式验证动作)就是交叉进行的,加载阶段尚未完成,连接阶段可能已经开始,但这些夹在加载阶段之中进行的动作,仍然属于连接阶段的内容,这两个阶段的开始时间仍然保持着固定的先后顺序。
Q:“什么情况下需要开始类加载过程的第一个阶段:加载?”
A:“Java虚拟机规范中并没有进行强制约束,这点(开始加载的时机)可以交给虚拟机的具体实现来自由把握。但是对于初始化阶段,虚拟机规范则是严格规定了有且只有被Java程序“首次主动使用”的类才会对其进行“初始化”(而加载、验证、准备自然需要在此之前开始)
Java程序对类的使用方式可以分为两种:
① 主动使用;
“主动使用”的7种情况:
[1] 创建类的实例
遇到 new 字节码指令(使用new关键字实例化对象的时候)
[2] 访问某个类或接口的静态变量。或者对该静态变量赋值
遇到 getstatic、putstatic 字节码指令(读取或设置一个类的静态字段的时候,被final修饰、已在编译期把结果放入常量池的静态字段除外)
[3] 调用类的静态方法
遇到 invokestatic 字节码指令(调用一个类的静态方法的时候)
[4] 反射调用
[5] 当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。
[6] Java虚拟机启动时被标明为启动类的类(包含main()方法的那个类)
[7] 当使用JDK 1.7的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化。
② 被动使用
除了以上七种情况,其他的使用Java类的方式都被看作是对类的“被动使用”,都不会导致类的初始化。
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-80669-1.html
在中国你不和政府好好关系
哥哥加油
我想我也可以不断地去追求的