类加载阶段:
一.加载:
1.将类的字节码载入方法区,内部采用C++的instanceKlass描述Java类,其重要的field有:
2.如果这个类有父类,优先加载父类
3.加载和连接可能是交替执行的
内存结构:
如果想通过对象找到类信息,现根据对象头找到Person.class,再由Person.class找到元空间的instanceKlass
二.链接
1.验证:
验证类是否符合JVM规范,安全性检查(如魔数检验)
2.准备:
为static变量分配空间,设为默认值
注意:
分配空间和赋值是两个阶段完成的,链接只是分配空间,赋值动作在初始化阶段完成
3.解析:
将常量池中的符号引用解析为直接引用
public class HelloWorld {
public static void main(String[] args) throws ClassNotFoundException {
ClassLoader classLoader = HelloWorld.class.getClassLoader();
//loadClass 方法不会导致类的解析和初始化,只会加载这个类
Class<?> c = classLoader.loadClass("com.ghc.jvm.classload.C");
}
}
class C{
D d=new D();
}
class D{}
JVM内存中类C,D仅仅是个符号,并没有关联真正的内存地址,是UnresolvedClass,当用到时才会进行解析和初始化
new C();
而new C()会触发类C的解析和初始话过程
可以看到C,D都被已经关联上了实际的内存地址
三.初始化阶段
调用<clinit>()V,虚拟机会保证这个类的构造方法的线程安全
即执行静态代码块static{}和初始化静态变量
发生的时机