加载器一:类的加载、连接和初始化

时间:2020-12-05 17:27:41

类的加载:

类的加载是指将类的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。