JVM类加载机制
- 类加载周期:加载-验证-准备-解析-初始化-使用-卸载(注意加载与类加载的关系)
- 类加载过程:加载-验证-准备-解析-初始化
- “初始化”触发
- 遇到new (getstatic putstatic invokestatic) 关键字 ,遇到读取、设置一个类的静态字段和调用类静态方法(final 修饰的变量 编译期初始化放到常量池,顾读取final 修饰的不会触发加载 记住new就可以了)
- 通过反射调用类
- 初始化子类,其父类没有进行初始化,触发父类初始化
- main()所在类
- 当使用jdk1.7动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getstatic,REF_putstatic,REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行初始化,则需要先出触发其初始化。(知道就好)
3.加载
数组类本身不通过类加载器创建,它是由JVm直接创建
非数组类开发人员可以控制其加载
4.验证
文件格式-元数据-字节码-符号引用验证(粗到细)
5.准备
内容:在方法区中分配内存,再为类静态变量分配内存并设置初始值,实例变量在对象实例化时一起分配到java堆中。
public static int value=123;
准备阶段过后、value=0;value=123是在初始化时de1<clinit>方法里执行
6.解析
………看书吧
7.初始化
类加载的最后一步,执行clinit()方法。
此方法由编译器收集所有变量赋值动作和静态语句块static{}中的语句合并产生(静态语句块只能访问静态语句块之前的变量)
子类clinit方法执行前父类经执行完毕,所以object()类clinit方法第一个执行。
同一个加载器中,同一个类clinit方法只能执行一次,所以clinit方法在多线程中会被加锁,但只能一个进程执行,并且,clinit方法可能造成阻塞。
8.类加载器
加载类classLoader,类相等(class对象的equal isInstance() inAssignableFrom 返回结果为真)的前提是同一个加载器加载。
双亲委派模型(除了启动类加载器,其他加载器都有父类加载器
JVM角度两种加载器:c++实现的启动类加载器和java实现的其他类加载器
开发人员角度:启动类加载器 扩展类加载器 应用程序类加载器
加载器调用:先调用加载器父类(因为这样,object才会在各种加载器中相等),若父类加载器抛出ClassnotFoundExption,则调用自己的加载方法。