前言
不了解 JVM 的类加载机制你也可以 coding, 但是当你了解之后, 可以让你在 coding 的时候避免很多坑, 本文将以一道常见的面试题去剖析一下. 本文参考 深入理解 Java 虚拟机 (第 2 版) .
- public class ClassLoadTest {
- private static ClassLoadTest test = new ClassLoadTest();
- static int x;
- static int y = 0;
- public ClassLoadTest() {
- x++;
- y++;
- }
- public static void main(String[] args) {
- System.out.println(test.x);
- System.out.println(test.y);
- }
- }
这里大家可以先猜测一下答案, 可能结果会出乎你的意料~
类加载过程
先用一个图简单的描述一下类加载的这个过程
image
加载
这个过程相当于从本地或者网络端去读取一个字节流, 然后将一些静态储存结构转换成方法区中运行时期的数据, 最后生成一个代表这个类的 Class 对象, 作为方法区访问这个类的入口.
例如:
咱们可以通过一个类的全限定名去加载类
通过 jar,war 包去加载类
通过 http 请求去第三方平台上拉取指定的类来加载
运行时计算生成, 例如 Cglib 动态代理等等
针对上述例子, 这里是加载一个 ClassLoadTest.class 对象.
验证
要理解这个环节并不是很难, 一个东西要放到 JVM 上去运行, 咱们肯定得对其进行一些过滤, 不能啥都往上丢, 这里的验证简单的举几个例子:
文件格式的验证:
1是否以魔数 0xCAFEBABE 开头;
2主次版本号是否在当前虚拟机处理范围内;
3常量池中的常量是否有不被支持的常量类型等等.
元数据的验证:
1这个类是否有父类;
2这个类的父类是否继承了不被允许继承的类 (final 修饰的类);
3这个类不是抽象类, 是否实现了所有接口中要实现的方法等等.
字节码的验证:
1保证跳转指令不会跳转到方法体以外的字节码指令上;
2保证方法体中的类型转换是有效的等等.
符号引用的验证:
1能否通过类的全限定名去找到对应的类;
2符号引用中的类, 字段, 方法是否可以被当前类访问等等.
准备过程
这个过程相当于给类变量分配内存并设置变量初始值的阶段, 这些变量所使用的内存都将在方法区中进行分配.
针对上述例子:
- test = null;
- x = 0;
- y = 0;
注意: 这里有个特殊情况, 如果该字段被 final 修饰, 那么在准备阶段改字段就会被设置成咱们自定义的值. public static final int value = 11 , 在准备阶段就会直接赋值 11, 并不是该变量的初始值.
解析过程
将符号引用转换成直接引用的过程. 这里有两个名词 符号引用 和 直接引用 .
符号引用: 符号引用与虚拟机的布局无关, 甚至引用的目标不一定加载到了内存中. 符号可以是任何形式的字面量, 只要使用时能够准确的定位到目标即可.
直接引用: 直接引用可以直接指向目标的指针, 相对偏移量或是一个能间接定位到目标的句柄. 直接引用与虚拟机布局有关, 如果有了直接引用, 那么引用的目标必定已经在内存中存在.
而解析过程又会针对类, 字段, 方法进行解析, 解析失败则会抛出相应的异常. 例如在解析时发现没有访问权限会抛出 java.lang.IllegalAccessException 异常, 查询不到引用字段会抛出 java.lang.NoSuchFieldException 异常, 查询不到方法会抛出 java.lang.NoSuchMethodException 异常等等.
初始化
在准备阶段, 变量已经赋值过系统要求的默认值, 在初始化阶段, 则会根据程序制定的主观计划去初始化类变量和其他资源. 这句话听起来有些绕口, 根据上述例子, 实际上就是:
- test = new ClassLoadTest();// x = 1;y =1
- y = 0;
这个过程, 由于 x 咱们自己并没有去设定一个值, 所以初始化阶段它不会发生任何改变, 但是 y 咱们有设定一个值 0, 所以最后造成最终结果为 x = 1;y = 0 .
ps: 在同一个类加载器下, 一个类只会初始化一次. 多个线程同时初始化一个类, 只有一个线程能正常初始化, 其他线程都会进行阻塞等待, 直到活动线程执行初始化方法完毕.
总结
对于上面这个面试题, 咱们用流程图简单的描述一下:
image
最后
后续会持续更新 JVM 专题知识及更多架构专题, 写的不好的地方也希望大牛能指点一下, 大家觉得不错可以点个赞在关注下我, 刚刚入驻, 以后还会分享更多文章!
来源: http://www.jianshu.com/p/cc05b8a91200