美文网首页
虚拟机类加载机制【类加载过程(一)加载】

虚拟机类加载机制【类加载过程(一)加载】

作者: 云芈山人 | 来源:发表于2021-07-29 23:46 被阅读0次

    “加载”是“类加载”(Class Loading)过程的一个阶段,在加载阶段,虚拟机需完成以下3件事情:

    1. 通过一个类的全限定名来获取定义此类的二进制字节流。
    2. 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
    3. 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
    • 虚拟机规范的这3点其实不算具体,所以虚拟机实现与具体应用的灵活度都是相当大的。
      如“通过一个类的全限定名来获取定义此类的二进制字节流”这条有以下获取方式:
      1. 从ZIP包中读取,这很常见,最终成为日后JAR、EAR、WAR格式的基础。
      2. 从网络中获取,这种场景最典型的应用就是Web Applet。
      3. 运行时计算生成,这种场景使用的最多的就是动态代理技术,在java.lang.reflect,Proxy中,就是用ProxyGenerator.generateProxyClass来为特定接口生成形式为“*$Proxy”的代理类的二进制字节流。
      4. 由其他文件生成,典型场景是JSP应用,即由JSP文件生成对应的Class类。
      5. 从数据库中读取,这种场景相对少见些,例如有些中间件服务器(如SAP Netweaver)可以选择把程序安装到数据库中来完成程序代码在集群间的分发。
      6. 可以从加密文件中获取,这是典型的防Class文件被反编译的保护措施,通过加载时解密Class文件来保障程序运行逻辑不被窥探。
      7. ......
    • 相对于类加载过程的其他阶段,这个非数组类的加载阶段(准确说是加载阶段中获取类的二进制字节流的动作)是开发人员可控性最强的,因为加载阶段既可以使用系统内置的引导类加载器,也可以自定义类加载器去完成,开发人员可通过定义自己的类加载器去控制字节流的获取方式(即重写一个类加载器的findClass()或loadClass()方法),实现根据自己想法赋予应用程序获取运行代码的动态性。
    • 对于数组类而言,本身不通过类加载创建,由Java虚拟机直接在内存中动态构造出来的,但数组类与类加载器仍然有很密切的联系,数组类的元素类型(ElementType,指的是数组去掉所有维度的类型)最终靠类加载器去创建,一个数组类创建过程需遵循以下规则:
      1. 如果数组类的组件类型(Component Type,数组去掉一个维度的类型)是引用类型,就递归采用之前描述的加载过程去加载这个组件,数组C将在加载该组件类型的类加载器的类名称空间上被标识(一个类必须与类加载器一起确定唯一性)。
      2. 如果数组的组件类型不是引用类型(如int[]),Java虚拟机将会把数组C标记为与引导类加载器关联。
      3. 数组类的可见性与它的数组类型的可见性一致,如果组件类型不是引用类型,那数组类的可见性将默认为public。
    • 加载阶段完成后,虚拟机外部的二进制字节流就按照虚拟机所需的格式(由虚拟机实现自行定义)存储在方法区之中,虚拟机规范未规定此区域的具体数据结构,然后在内存中实例化一个java.lang.Class类的对象(并没明确规定在堆中,HotSpot虚拟机而言,Class对象比较特殊,虽然是对象但存放在方法区里),这个对象将作为程序访问方法区中的这些类型数据的外部接口。
    • 加载阶段与连接阶段的部分内容(如一部分字节码文件格式验证动作)是交叉进行的,加载阶段尚未完成,连接阶段可能已经开始,但这些夹在加载阶段之中进行的动作,仍然属于连接阶段的内容,这两个阶段的开始时间仍然保持着固定的先后顺序。

    相关文章

      网友评论

          本文标题:虚拟机类加载机制【类加载过程(一)加载】

          本文链接:https://www.haomeiwen.com/subject/xaxtvltx.html