每天进步一点点!
在前面的几篇中, 我们已经详细学习了 Class 字节码文件的结构, 包含哪些内容已经内容的含义, 下面几篇我们将研习一下类的加载.
虚拟机的类加载机制: 虚拟机把描述类的数据从 Class 文件加载到内存, 并对数据进行校验, 转换解析和初始化, 最终形成可以被虚拟机直接使用的 Java 类型.
整个生命周期包括: 加载 (Loading), 验证(Verification), 准备(Preparation), 解析(Resolution), 初始化(Initialization), 使用(Using) 和 卸载(Unloading) 七个阶段.
其中, 加载, 验证, 准备, 初始化和卸载这 5 个阶段的顺序是确定的.
加载到内存中的类都包含哪些信息我们在前面已经学习过了, 大家还记得吗? 包括魔数, java 版本, 常量池, 类的访问标识, 类名, 父类名, 接口信息, 字段, 方法和属性等.
而对于虚拟机来说, 类又是可以在运行期动态加载, 动态连接 (验证, 准备, 解析三个部分统称为连接) 的.
解析阶段则不一定: 因为 java 支持运行时绑定(也叫动态绑定或晚期绑定, 绑定: 就是将一个方法的调用与方法所在的类关联起来).
什么是动态绑定? 在程序执行期间根据对象的类型进行绑定, 这也是 java 的默认绑定方式, 几乎所有的方法都是后期绑定.
那么, 动态的绑定的意义是什么呢? 简单是为了实现多态, 比如当方法中参数是父类或者接口的时候.
与之相对应的还有一个概念动态绑定 (前期绑定), 也就是在程序执行前(编译期间) 进行绑定, final,static,private 和构造方法都是前期绑定.
下面我们来看看来加载的具体过程.
加载: 虚拟机对加载的开始时间没有强制约束.
初始化: 以下 5 种情况有可能进行初始化操作.
1. 当虚拟机执行 new,getstatic,putstatic 和 invokestatic 这四条字节码指令的时候, 虚拟机会先查询该类是否已经初始化过, 如果没有, 则需要先将该类进行初始化. 比较常见的场景:
使用 new 关键字实例化对象的时候;
读取或设置一个类的静态字段 (被 final 修饰, 已在编译器把结果放入常量池的静态字段除外) 的时候;
调用一个类的静态方法的时候.
2. 使用 java.lang.reflect 包的方法对类进行反射调用的时候, 如果类没有进行过初始化, 则需要先触发其初始化.
3. 当初始化一个类的时候, 如果发现其父类还没有进行过初始化, 则需要先触发其父类的初始化.
4. 当虚拟机启动时, 用户需要指定一个要执行的主类 (包含 main() 方法的那个类), 虚拟机会先初始化这个主类.
5.
当使用 jdk1.7 动态语言支持时, 如果一个 java.lang.invoke.MethodHandle 实例最后的解析结果 REF_getstatic,REF_putstatic,REF_invokeStatic 的方法句柄, 并且这个方法句柄所对应的类没有进行初始化, 则需要先出触发其初始化.
喜欢文章或想一起学习的朋友可以关注我, 给我点赞, 我将会持续更新, 有什么疑问或文中有不当之处请给我留言, 真诚地希望能与大家一起交流探讨, 学习进步.
来源: http://www.jianshu.com/p/9b5253622182