一.klass模型
-
klass模型类的继承结构
-
普通的Java类在JVM中对应的是instanceKlass类的实例
2.1 InstanceMirrorKlass:用于表示java.lang.Class,Java代码中获取到的Class对象,实际上就是这个C++类的实例,存储在堆区,学名镜像类
2.2 InstanceRefKlass:用于表示java/lang/ref/Reference类的子类
2.3 InstanceClassLoaderKlass:用于遍历某个加载器加载的类
-
Java中的数组不是静态数据类型,是动态数据类型,即是运行期生成的,Java数组的元信息用ArrayKlass的子类来表示:
3.1TypeArrayKlass:用于表示基本类型的数组
3.2 ObjArrayKlass:用于表示引用类型的数组
二.类加载的过程(生命周期)
-
加载
1.1要求
通过类的全限定名获取存储该类的class文件(没有指明必须从哪获取)
解析成运行时数据,即instanceKlass实例,存放在方法区
在堆区生成该类的Class对象,即instanceMirrorKlass实例1.2 何时加载
1.2.1主动使用时
1、new、getstatic、putstatic、invokestatic
2、反射
3、初始化一个类的子类会去加载其父类
4、启动类(main函数所在类)
5、当使用jdk1.7动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getstatic,REF_putstatic,REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行初始化,则需要先出触发其初始化
Demo:
1.根据调用链可以看出,子类没有被调用,在懒加载过程中,子类是不进行初始化的,同时父类在加载过程,先加载静态代码块,然后压栈,所以最后输出结果如下
2.子类调用会加载父类
3.final修饰静态常量,类不用加载
4.final 修饰的静态变量,类是需要加载的
5.反射调用过程中当前类会加载
1.2.2 预加载
包装类、String、Thread
-
验证
1、文件格式验证
2、元数据验证
3、字节码验证
4、符号引用验证 -
准备
为静态变量分配内存、赋初值
实例变量是在创建对象的时候完成赋值的,没有赋初值一说
如果被final修饰,在编译的时候会给属性添加ConstantValue属性,准备阶段直接完成赋值,即没有赋初值这一步
-
解析
将常量池中的符号引用转为直接引用
解析后的信息存储在ConstantPoolCache类实例中
1、类或接口的解析
2、字段解析
3、方法解析
4、接口方法解析
何时解析
思路:
1、加载阶段解析常量池时
2、用的时候
openjdk是第二种思路,在执行特定的字节码指令之前进行解析:
anewarray、checkcast、getfield、getstatic、instanceof、invokedynamic、invokeinterface、invokespecial、invokestatic、invokevirtual、ldc、ldc_w、ldc2_w、multianewarray、new、putfield
- 初始化
执行静态代码块,完成静态变量的赋值
静态字段、静态代码段,字节码层面会生成clinit方法
方法中语句的先后顺序与代码的编写顺序相关