classLoader体系, 类的初始化过程

以下内容全部摘自<<深入Java虚拟机第二版>>

Java虚拟机有两种类装载器:启动类装载器和用户自定义类装载器.
前者是Java虚拟机实现的一部分,后者是Java程序的一部分.由不同的类装载器装载的类将被放在虚拟机内部的不同命名空间中.

类装载器子系统涉及Java虚拟机的其它几个组成部分,以及几个来自java.lang类的库.比如,用户自定义类装载器是普通的Java对角,它的类必须派生自java.lang.ClassLoader类.ClassLoader中定义的方法为程序提供了访问类装载器机制的接口.此外,对于每一个被装载的类型,Java虚拟机都会为它创建一个java.lang.Class类的实例来代表该类型.和其它对象一样,用户自定义的类装载器以及Class类的实例都放在内存中的堆区,而装载的类型信息都位于方法区.

Java虚拟机通过装载,连接和初始化一个Java类型,使该类型可以被正在运行的Java程序所使用.

其中, 装载就是把二进制形式的Java类型读入Java虚拟机中;

连接就是把这种已经读入虚拟机的二进制形式的类型数据合并到虚拟机的运行时状态中去.

连接阶段分为三个子步骤: 验证,准备和解析.

  验证步骤确保了Java类型数据格式正确并且适于Java虚拟机使用,

  而准备步骤则负责为该类型分配所需内存,比如为它的类变量为分配内存.

  解析步骤则负责把常量池中的符号引用转换为直接引用.虚拟机的实现可以推迟解析这一步,它可以在当运行中的程序真正使用某个符号引用时再去解析它(把该符号引用转换为直接引用).

当验证,准备和(可选的)解析步骤都完成了时,该类型就已经为初始化做好了准备,在初始化期间,都将给类变量赋以适当的初始值.

Java虚拟机规范规定所有的Java虚拟机必须实现在每个类或接口首次主动使用时初始化.
下面这六种情况符合主动使用的要求:

.当创建某个类的新实例时(或者通过在字节码中执行new指令;或者通过不明确的创建,反射,克隆或者反序列化).
.当调用某个类的静态方法时(既在字节码中执行invokestatic指令时).
.当使用某个类或接口的静态字段,或者对该字段赋值时(即在字节码中,执行getstatic或putstatic指令时),用final修饰的静态字段除外,它被初始化为一个编译时的常量表达式.
.当调用Java API中的某些反射方法时,比如类Class中的方法或者java.lang.reflect包中的类的方法.
.当初始化某个类的子类时(某个类初始化时,要求它的超类已经被初始化了).
.当虚拟机启动时某个被标明为启动类的类(即含有main()方法的那个类).

除上述六种情况,所有其它使用Java类型的方式都是被动的使用,不会导致Java类型的初始化.

你可能感兴趣的:(java,虚拟机)