Java类加载机制--类加载过程(加载)

Java虚拟机加载类的全过程包括:加载、验证、准备、解析、初始化。验证、准备、解析叫链接过程。今天咱们讲加载。
首先明确“加载”是“类加载”的一个过程,不要混淆。加载过程当中,虚拟机须要完成下列三个事情:java

  1. 经过一个类的全限定名获取定义此类的二进制字节流;
  2. 将这个字节流所表明的静态存储结构转化为方法区运行时的数据结构;
  3. 在内存中生成一个表明这个类的java.lang.Class对象,做为方法区这个类的各类数据的访问入口。

虚拟机的这三点要求不算具体,所以虚拟机实现与具体应用的灵活度都是至关大的。就拿第一条说,他仅仅要求“经过一个类的全限定名获取定义此类的二进制字节流”,并无指明二进制字节流要从Class文件获取,也没说要怎样获取,从哪里获取。因此说java虚拟机的设计团队在加载阶段搭建了一个很广阔的舞台,许多举足轻重的java技术都创建在这个舞台上,好比:web

  • 从ZIP包中获取,这是jar,war格式的基础
  • 从网络中获取,这种场景的典型应用就是Applet
  • 运行时计算生成,这种场景使用的最多的就是动态代理技术,在java.lang.reflect.Proxy中,就是用了ProxyGenerator.generateProxyClass来为特定接口生成形式为“*$Proxy”的代理类的二进制字节流
  • 由其余文件生成,典型的场景是JSP应用,即JSP文件生成对应的Class类
  • 从数据库中读取,这种场景相对少见

相对于类加载过程的其余阶段,一个非数组类的加载阶段(准确的说,是加载阶段中获取二进制字节流的动做,有的加载阶段不获取二进制字节流)是开发人员 可控性最强的,由于加载阶段便可以使用系统提供的引导类加载器来完成,也能够由用户自定义的类加载器去完成,开发人员能够经过定义本身的类加载器去控制字节流的获取方式(即重写一个类的loadClass方法)。数据库

对于数组类而言,状况不一样。数组类自己不经过类加载器建立,他是由java虚拟机直接建立。但数组类与类加载器的关系任然很密切,由于数组类的元素类型(指的是数组去掉全部维度的类型)最终要靠类加载器建立,一个数组类(下面简称C)建立过程遵循如下规则:数组

  • 若是数组的组件类型(指的是数组去掉一个维度的类型)是引用类型,那就递归采用本节中定义的加载过程去加载这个组件类型,数组C将在加载该类型组件的类加载器的类名称空间上被标识(这点很重要,一个类必须与类加载器一块儿肯定惟一性)
  • 若是数组的组件类型不是引用类型(例如int[]数组),Java虚拟机将会把数组C标记为与引导类加载器关联
  • 数组类的可见性与他的组件类型的可见性一致,若是组件类型不是引用类型,那数组类的可见性将默认为public

加载阶段完成以后,虚拟机外部的二进制字节流就按照虚拟机所需的格式存储在方法区之中,方法区中的数据存储格式由虚拟机实现自行定义,虚拟机规范未规定此区域的具体数据结构。而后在内存中实例化一个java.lang.Class类的对象(并无明确规定是在java堆中,对于HotSpot虚拟机而言,Class对象比较特殊,他虽然是对象,可是放在方法区中),这个对象将做为程序访问方法区中的这些类型数据的外部接口。
加载阶段与链接阶段的部份内容(如一部分字节码文件格式验证动做)是交叉进行的,加载阶段还没有完成,链接阶段可能开始了,可是这些夹在加载阶段之中进行的动做,任然属于链接阶段的内容,这两个阶段的开始时间任然保持着固定的前后顺序。网络