当程序主动使用某个类时,如果该类还未被加载到内存中,系统会通过加载、连接、初始化三个步骤来对该类进行初始化,如果没有意外,JVM将会连续完成这三个步骤。
一.加载:
类加载指的是将类的class文件读入内存,并为之创建一个java.lang.Class对象,也就是说当程序中使用任何类时,系统都会为之建立一个java.lang.Class对象。
类的加载由类加载器完成,类加载器通常由JVM提供,JVM提供的这些类加载器通常被称为系统类加载器。除此之外,开发者可以通过继承ClassLoader基类来创建自己的类加载器。
通过使用不同的类加载器,可以从不同来源加载类的二进制数据,通常有如下几种来源:
1、从本地文件系统来加载class文件。
2、从JAR包中加载class文件,这种方式也是很常见的,JVM可以从JAR文件中直接加载该class文件。
3、通过网络加载class文件。
4、把一个Java源文件动态编译、并执行加载。
类加载器通常无须等到“首次使用”该类时才加载该类,Java虚拟机规范允许系统预先加载某些类。
二.类的连接:
当类被加载之后,系统为之生成一个对应的Class对象,接着将会进入连接阶段,此时将会负责把类的二进制数据合并到JRE中。类连接又可以分为如下三个阶段:
- 验证:用于检验被加载类是否有正确的内部结构,并和其他类协调一致。
- 准备:负责为类的静态属性分配内存,并设置默认初值。
- 解析:将类的二进制数据中的符号引用替换成直接引用。
三.类的初始化:
类的初始化阶段,主要就是对静态属性进行初始化。
Java类中对静态属性指定初始值有两种方式:声明静态属性时指定初始值和使用静态初始化块为静态属性指定初始值。
JVM初始化一个类包含如下步骤:
- 假如这个类还没有被加载和连接,程序先加载并连接该类
- 假如该类的直接父类还没有初始化,则先初始化其直接父类
- 假如类中有初始化语句,则系统依次执行这些初始化语句。
类初始化的时机:
- 创建类的实例:new,反射等。
- 调用某个类的静态方法
- 访问某个类或接口的静态属性
- 使用反射方式来强制创建某个类或接口对应的Class的对象。
- 初始化某个类的子类,该子类的所有父类都会被初始化。
- 直接使用java命令来运行某个类,当运行某个主类时,程序会先初始化该主类。
**特殊情况:
- 对于一个final型的静态属性,如果该属性可以在编译时就得到属性值,则可认为该属性可被当成编译时常量。当程序使用编译时常量时,系统会认为这是对该类的被动使用,所以不会导致该类的初始化。
- 如果final类型的静态属性的值不能在编译时得到,必须等到运行时才可以确定,如果通过该类来访问该静态属性,则可以认为是主动访问使用该类,将会导致该类被初始化。
- 当使用ClassLoader类的loadClass方法来加载某个类时,该方法只是加载该类,并不会执行该类的初始化。当使用Class的forName静态方法才会导致强制初始化该类。
|
|