类加载过程

注意不是对象的实例化过程
类加载过程不会调用任何构造器和non-static代码块等等
一个类加载,链接,初始化走完,然后才会考虑实例化的事情
类加载过程_第1张图片

加载

类加载器将classfile加载到方法区中,在堆中生成一个该类的Class对象,作为方法区这些数据的访问入口
方法区中使用C++的instanceKlass来描述Java类
instanceKlass重要的字段:
_java_mirror:类的Class实例(作用是使Java能够间接访问到instanceKlass)
_super:父类
_fields:成员变量
_methods:方法
_constants:常量池
_class_loader:类加载器
_vtable:虚方法表
_itable:接口方法表
如果这个类的父类还没加载,会先加载父类
加载和链接可能是交替执行的

类加载过程_第2张图片

链接

1.验证
检查classfile是否符合规范,安全性检查

2.准备
为static变量分配空间,设置默认值(0,NULL,false等)
(static变量在JDK6存储在instanceKlass末尾,JDK7开始存储于_java_mirror末尾)
static变量如果是final的基本类型或者String常量,赋值操作在准备阶段也会完成
注意:(实例变量是在对象实例化时随着对象一起分配的,和static变量也不在一个位置)

3.解析
将常量池中的符号引用解析为直接引用

初始化

调用<clinit>()方法
触发的时机:(总结:懒惰的,非必要不进行)
1.第一次Class.forName
2.第一次读取该类的static变量(不是<final-基本类型或字符串常量>)
	# 读取这种不会触发初始化
	final static String a = "vegew";
	final static int a = 3;
	# 读取这种会触发初始化
	static int a = 3;
3.第一次new对象的时候(static代码块只有第一次new的时候才触发,每次new的时候都会执行构造器和non-static代码块)
// 会触发static代码块
// 不会触发Tom类的构造函数和non-static代码块
Class.forName("cn.study.Tom"); // 注意:重复调用,初始化步骤也只会执行一次

// 不会触发Tom类的初始化步骤(Tom类加载阶段就会生成这个mirror对象)
System.out.println(Tom.class);
// 懒惰实例化
// 初始化时的线程安全是有保障的
class Singleton {
    private Singleton(){}
    private static class LazyHolder {
        private static final Singleton SINGLETON = new Singleton();
        static {
            System.out.println("======");
        }
    }
    // 第一次调用getInstance时,才会导致内部类加载和初始化静态成员,注意不会创建内部类对象,只是广义加载-(加载(狭义)->链接->初始化)
    public static Singleton getInstance(){
        return LazyHolder.SINGLETON;
    }
}

类加载过程_第3张图片
java类的初始化和实例化区别
java类和对象的生命周期

你可能感兴趣的:(JVM,java,jvm)