类的加载
类的加载就是把class文件加载到虚拟机中,结果就是以一种虚拟机认识的形式存在,JAVA虚拟机是用C++进行编码的,所以类加载到虚拟机中会被解析为C++中的结构体。
类的存在形式
其实类加载到虚拟机中会以不同的形式存在,这里主要是普通的类与数组存在区别。普通的类加载到虚拟机中会生成一个instanceKlass对象,数组会生成ArrayKlass对象。instanceKlass是被分配到方法区中的。
除了上述的instanceKlass对象之外,jvm还会在堆区分配一个MirrorKlass对象,这个对象就是java中的Class对象,他会有一个指向instanceKlass的引用,同样instanceKlass也会存在一个对MirrorKlass的引用。
类的加载过程
加载
加载就是完成从class文件到转换为instanceKlass实例的过程,生成的instanceKlass实例会存放到方法区,并生成一个Class实例放到堆中。
验证
验证class文件的正确性,实际jvm代码运行中是边加载边验证
准备
静态变量赋初值
这里的初值不是实际的值,而是根据类型赋初始值
解析
根据静态常量池生成运行时常量池,即由逻辑地址转换为物理地址 符号引用->直接引用
初始化
执行方法,完成静态变量赋值
初始化的时机
1、new、getstatic、putstatic、invokestatic
2、反射
3、初始化一个类的子类会去加载其父类
4、启动类(main函数所在类)
5、当使用jdk1.7动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getstatic,REF_putstatic,REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行初始化,则需要先出触发其初始化
注意
1、类加载完成并不一定会执行初始化
可以理解为:new的时候会完成类的加载,然后初始化
但是类的加载不一定是new来触发的,比如
public class Test_1 {
public static void main(String[] args) {
System.out.printf(Test_1_B.str);
while (true);
}
}
class Test_1_A {
public static String str = "A str";
static {
System.out.println("A Static Block");
}
}
class Test_1_B extends Test_1_A {
static {
System.out.println("B Static Block");
}
}
这种情况下Test_1_B会被加载但是不会执行初始化
2、构造方法是在new的时候触发的
hsdb的使用
jconsole
visulVm
java -XX:+printFlagsFinal -version |grep “”