类的加载:
类的加载是指将类的class文件读入内存中,并为之创建一个java.lang.Class对象,也就是当程序使用任何类是,系统都会为之建立一个java.lang.Class对象(也可以说类是java.lang.Class的实例,详情请百度‘java.lang.Class’)
类的加载使用类加载器完成,JVM提供了几种类加载器以完成类的加载。除此之外,开发者可以通过继承ClassLoader来创建自己的类加载器。
通常可以使用不同的类加载器从不同的来源加载类的二进制数据:
从本地文件系统加载class文件,这是通常情况下的类加载方式 |
|
从jar包加载class文件,这种方式也是很常见的,例如:JDBC编程时用到的数据库驱动加载Class.forName("");就是放在jar包中,JVM可以从jar中直接加载改class文件。 |
|
通过网络加载class文件 |
|
把一个java源文件动态编译,并执行加载 |
类加载器通常无需等到“首次使用”该类时才加载该类,Java虚拟机规范允许系统预先加载某些类。
类的连接:
当类被加载后,系统会生成一个对应的Class对象,接着将会进入到连接阶段,连接阶段负责把类的二进制数据合并到JRE中。类连接又可分为以下三个阶段。
验证: | 验证阶段由于检查被加载的类的内部结构是否正确,并协调与其他类的关系型 |
|
准备: | 类准备阶段负责为类变量分配内存,并设置默认的初始值 |
|
解析: | 将类的二进制数据长得符号引用替换成直接引用 |
类的初始化:
虚拟机负责对类进行初始化,主要是对类变量的初始化。在Java类中对类变量之低昂初始值有两种方式:①舍命类变量时指定初始值;②使用静态初始化块为类变量指定初始值。
如下所示:
public class Test { // 声明变量a时指定初始值 static int a = 5; static int b = 9; // ① static int c; static { // 使用静态初始化块为变量b指定出初始值 b = 6; System.out.println("----------"); } ...... }
程序为类变量a、b都显式指定了初始值,分别是5/6,但类变量c则没有指定,它采取默认值0;
声明变量时指定初始值,静态初始化快都将被当成类的初始化语句,JVM会按照这些语句在程序中的排序顺序依次执行它们
如下所示:
public class Test { static { // 使用静态初始化块为变量b指定出初始值 b = 6; System.out.println("----------"); } // 声明变量a时指定初始值 static int a = 5; static int b = 9; // ① static int c; public static void main(String[] args) { System.out.println(Test.b); } }
上面的代码现在静态初始化块中为b赋值为6;接着程序向下执行,执行到①号代码处,由于这行也属于该类的初始化语句,所以在此为b变量赋值。最终b变为9。
JVM初四花一个类包含如下几个步骤:
假如这个类还没有被加载和连接,则程序先加载并连接该类。 |
|
假如该类的父类还没有被初始化,则先初始化其直接父类。 |
|
假如类中有初始化语句,则系统依次执行这些初始化语句。 |
补充②:当系统初始化直接父类时,也是按照这三个步骤;当直接父类还有父类时,则再次重复这三个步骤......以此类推,所以JVM最先初始化的总是java.lang.Object。