类加载机制的学习4___类加载的过程

     通过之前的学习,我们知道:类加载就是根据一个类的全限定名,将其字节码文件 加载到JVM内部,并创建java.lang.Class对象实例。其实,一个类的加载过程应包括:加载,连接(验证,准备,解析),初始化。

加载:

   通过类加载器,根据一个类的全限定名,将该类的字节码文件加载到JVM中(存储在方法区内),再创建java.lang.Class对象实例,由于JVM规范中并没有要求Class对象实例应该是否应该存放在堆区中,在HotSpot VM中将Class对象实例存储在方法区内。该方法区中的Class对象实例,就会作为日后访问该类数据的入口。

连接:

连接是将JVM中的二进制字节流的类数据信息合并到JVM的运行时状态中。连接阶段又是由:验证,准备,解析 3个阶段组成。

  1. 验证:主要任务是验证类的数据信息是否符合JVM的规范,是否是一个有效的字节码文件;
  2. 准备:主要是给类中的静态变量分配内存空间,并赋初始值;
  3. 解析:主要任务是将常量池中的所有符号引用变成直接引用;

注意:Java虚拟机中并没有明确要求解析阶段必须得在初始化之后,因此可以先进行类的初始化阶段,在进行解析阶段。

初始化:

该阶段中,JVM会把程序中所有标识static关键字的语句全部执行一遍,会覆盖在连接的准备阶段所赋的初始值,在初始化阶段 JVM还会执行static块中的所有操作。

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

小总结:类的加载总共包含三个阶段:加载,连接,初始化。

  1. 加载:由类加载器根据类的全限定名,采用双亲委派机制将类的字节码文件加载进JVM中,并创建Class实例对象。
  2. 连接:该阶段主要是将,加载进JVM中的二进制字节流数据的类信息合并到JVM的运行时中来,其中包括三个阶段:

              验证:检查类的数据信息是否满足JVM的规定,以及二进制字节码文件是否满足规定;

              准备:给类中的static静态变量分配内存空间,并赋初始值;

              解析:将常量池中的所有符号引用全部变成直接引用。

         3.初始化:执行类中的所有static语句,也包括static块。

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

初始化操作的时机选择:

Java虚拟机对加载和连接的时机选择有很大的灵活性,但是对于初始化,却有着规范限制,一个类或者接口应该在第一次主动使用时完成初始化操作,具体包括:

  1. 在给一个类创建新对象时:包括new,反射,序列化。
  2.  调用一个的静态方法时;
  3. 调用Java API中的反射方法时;
  4. 初始化一个派生类时(其超类必须已经完成初始化操作)接口中并不适合 因为当调用超接口的非静态字段时 必须完成初始化操作;
  5. JVM启动包含main方法的类时;
  6. 调用一个类或者接口的静态字段时,并给这些静态字段进行赋值操作;

   

public class Test {
    static{
        //构造方法被执行
        new Test();
    }
    static int v1;
    static int v2=0;
    public Test(){
        v1=10;
        v2=10;
        System.out.println("构造函数被执行");
        System.out.println("v1"+v1); //10
        System.out.println("v2"+v2); //10
    }

    public static void main(String[] args) {
        System.out.println("v1"+v1); //10
        System.out.println("v2"+v2); //0
    }
}

代码分析:static代码块是按顺序进行执行的,后来的值也会覆盖原来的值。

猜你喜欢

转载自www.cnblogs.com/xbfchder/p/11428791.html