【Java】「深入理解Java虚拟机」学习笔记(5)- 类加载

  C/C++在编译时需要进行连接,而Java的类加载、连接和初始化是在运行时完成的。 

     图  类的生命周期

  图中解析的过程不一定在准备和初始化之间,也可以在初始化之后再开始,以支持Java的运行时动态绑定。

一、类加载过程

  1、加载

    加载是整个“类加载”过程的第一个阶段。这一步也叫“加载”,可以理解为把类从文件中读取到内存中并按一定数据结构保存以备后续使用。

    主要分为三个步骤:

       ①通过类的全限定名获取其字节码。

      ②将字节码中的静态存储结构转换成方法区的运行时数据结构。

      ③在内存中创建一个代表这个类的java.lang.Class对象,作为该类的元数据访问入口。那么你现在知道了反射的时候,someClass.class这个对象是怎么来的了吧?只要拿到这个class你想创建实例、调用方法都行,想干哈就干哈。

    数组的加载有所不同,因为数组本身是VM自己创建的,但数组中的元素类型可能是类,还是要靠类加载器去加载。所以数组的加载分两种情况:

      ①当数组的类型是引用类型,那就递归按照上面的方法加载。

      ②当数组的类型是基本数据类型如int [],则VM将会将该数组标记为与Bootstrap加载器关联。

  2、验证

    验证的目的是确保当前字节码文件中的内容,符合当前VM的要求,不会给VM运行造成危害。

    验证过程包括:文件格式验证、元数据验证、字节码验证和符号引用验证。 

    这一步作用类似于语法检查。因为字节码的编译是在JVM之外进行的(可能来自本地jar包甚至网络),不同版本的编译器生成不同版本规范的字节码,可能带来兼容性问题。另外,也能防范恶意的字节码修改影响虚拟机的运行稳定。   

  3、准备

    这个过程主要是为类变量分配内存(分配在方法区中)并赋默认初值(如int的初值为0,char为'u0000')。

  4、解析

    解析是将常量池内的符号引用替换为直接引用的过程。

  5、初始化

    初始化就是执行构造方法的过程。

♣所以你应该知道了成员变量初始化时刻有两次

  一次是在类加载的准备过程中、然后就是在调用构造方法的时候。

二、类加载器

  类加载器有各自的类名称空间,两个类加载器即使加载了同一个.class文件,生成的类被认为是不同的类。这也可以理解,它们在方法区本来保存的就是两份。

  1、类加载器分类

  

  2、双亲委派模型

    双亲委派的流程就是甩锅的过程。Bootstrap是顶层Loader,UserDef是底层Loader。底层Loader在接到类加载指令时啥也不干,把锅直接甩给上一层Loader,依次类推

  直到锅甩到Bootstrap(也就是说所有的锅都会到它这儿)。如果Bootstrap的路径里有这个类,算它倒霉它加载,否则它再把锅弹回给下一层Loader—Extension,如果

  Extension的类路径里有这个类,它加载。依次类推。。。

    双亲委派模型的好处是:它的这种上层优先的层级关系保证了,类加载的有序性,不会因为各路Loader自行加载导致的混乱。

PS:Tomcat的类加载机制

  https://blog.csdn.net/varyall/article/details/81610620  

原文地址:https://www.cnblogs.com/tigerhsu/p/9933282.html