第五章(一) 加载、链接、初始化-运行时常量池和启动

    Java虚拟机动态的加载、链接、初始化类或接口。加载是通过特定的名字找到类或接口类型的二进制表示,根据找到的二进制表示创建类或接口的过程。链接是获得创建的类,将它们结合进Java虚拟机的运行时状态以使他们能够被执行的过程。初始化一个类或接口包括执行类或接口的初始化方法<clinit>.
5.1 运行时常量池
    Java虚拟机为每一个类型维续一个常量池,一种运行时的数据结构,提供类似于传统语言中符号表的服务。
    类或接口的二进制表示中的常量池表被用来在类或接口创建时构建运行时常量池。运行时常量池中的所有引用都是原始的符号,常量池中的引用按照如下规则从类或接口的二进制表示中推断出来:
   
  • 一个类或接口的符号引用从类或接口的二进制表示的CONSTANT_Class_info中推断出来。这个引用按照Class.getName方法的返回值的形式给出类或接口的名字,即:
  •         - 对于非数组的类或接口,这个名字就是对应类或接口的二进制名字。
            - 对于n维的数组,这个名字以n个ASCII字符"["开头,紧跟着数组的元素类型:
                   > 如果元素是基本类型,就是相应的类型的描述符(B C D F I J S Z)对应着 byte char double float int long short boolean
                   > 否则,对应的元素就是引用类型,这时会用ASCII字符"L"加上对应元素的二进制名字,并在后面加上ASCII字符";"来表示。

             以上信息可以通过javap -v {className} 命令查看
             本章节中只要提及类或接口的名字,都是指Class.getName方法的返回值的形式。
  • 对一个类或接口的字段的符号引用由类或接口的二进制表示中的CONSTANT_Fieldref_info结构中推导出来。这样一个符号引用会给出对应字段的名字和描述符,还会给出这个字段所在类或接口对应的符号引用。
  • 对一个类的方法的符号引用由类或接口的二进制表示中的CONSTANT_Methodref_info结构中推导出来。这样一个符号引用会给出对应方法的名字和描述符,还会给出这个方法所在类对应的符号引用。
  • 对一个接口的方法的符号引用由类或接口的二进制表示中的CONSTANT_InterfaceMethodref_info结构中推导出来。这样一个符号引用会给出对应方法的名字和描述符,还会给出这个方法所在类对应的符号引用。
  • 对一个method handle的符号引用,由类或接口的CONSTANT_MethodHandle_info结构中推导出来。根据method handle类型的不同,这样一个引用可以给出一个类或接口的字段符号引用,或者是类的一个方法的引用,或者是一个接口的方法的引用。
  • 对一个method type的符号引用从CONSTANT_MethodType_info结构中推导出来,这样的一个引用给出一个方法的描述符。
  • 对一个call site specifier的符号引用从CONSTANT_InvokeDynamic_info结构中推导出来,这样的引用会给出:
  •        - 一个method handle的符号引用,这个引用会在invokedynamic指令中作为一个启动方法。
           - 一连串的符号引用(对一个类、方法类型、method handle),字符串字面值,运行常量值,它们会做为启动方法的静态参数。
            - 一个方法名字和一个方法描述

另外,非符号引用的运行时常量值从constant_pool中查找:
  • 一个字符串字面值是一个String类型的引用,从CONSTANT_String_info结构中推导出来,CONSTANT_String_info结构是一系列的Unicode码组成了字符串字面值。
  •     Java编程语言要求相同的字符串字面值一定要指向相同的String类实例。另外,如果一个任意字符串的String.intern方法被调用,如果这个字符串之前已经出现过,那么返回结果将是同一个类实例。因此下面的表达式的结果是true
          
    ("a" + "b" + "c").intern() == "abc"

        为了推导出字符串字面值,Java虚拟机会用下面的规则检测CONSTANT_String_info结构的字符序列:
              - 如果一个String类实力已经调用过它的intern方法,并且这个这个字符串拥有和CONSTANT_String_info结构一样的Unicode 码序列,那么这个字符串字面值就是同一个字符串实例的一个引用。
              - 否则一个新的包含了CONSTANT_String_info结构中Unicode码序列的字符串实例就会被创建,一个指向新创建的字符串的引用作为字符串字面值的结果,最终,这个新字符串的intern方法被调用。
  • 运行时常量数值从CONSTANT_Integer_info,CONSTANT_Float_info, CONSTANT_Long_info, 、CONSTANT_Double_info结构中推导出来
  •     类或接口的二进制表示常量池表中其他的结构有CONSTANT_NameAndType_info和CONSTANT_Utf8_info,它们仅被直接用来推导出类、接口、字段、方法、方法类型、method handles的符号引用,或者是用来推导出字符串字面值和call site说明符。

    5.2 Java虚拟机启动
        Java虚拟机通过创建一个初始化类类启动,利用引导类加载器。Java虚拟机紧接着链接、初始化这个类,调用它的public void main(String[]) 类方法。对这个方法的调用带动所有的后续操作。执行组成main方法的Java虚拟机指令可能会引起链接其他的类或接口,也可能会调用其他的方法。
        在Java虚拟机的实现中,初始化类可以通过命令行参数提供。或者实现者也可以提供一个设定类加载器的初始化类,用这个类加载器来加载一个应用。

    猜你喜欢

    转载自fengyilin.iteye.com/blog/2273580