Advanced Java-07-字节码

一些有关Java字节码的文章:

字节码相关库

可以操作字节码的库:

  • JVM Tool Interface (JVMTI): Java Bytecode and JVMTI Example,这是一些使用 JVM Tool Interface 操作字节码的比较实用的例子。包括方法调用统计、静态字节码修改、Heap Taggin 和 Heap Walking。计、静态字节码修改、Heap Taggin 和 Heap Walking
  • asm tools - 用于生产环境的 Java .class 文件开发工具。
  • Byte Buddy - 代码生成库:运行时创建 Class 文件而不需要编译器帮助。

多态性实现机制

方法绑定

Class 文件的编译过程中不包含传统编译中的连接步骤,一切方法调用在 Class 文件里面存储的都只是符号引用,而不是方法在实际运行时内存布局中的入口地址。
一部分方法的符号引用在类加载阶段或第一次使用时转化为直接引用,这种称为 静态绑定
另一部分方法在类运行期间才能确定某些目标方法的直接引用,称为 动态绑定

Java 字节码中与调用相关的指令共有五种(还有一种invokedynamic,比较复杂):

  • 静态绑定: 调用哪个方法在编译期就确定了, 在类的加载阶段, static/final/private方法的符号引用被替换为直接引用, 用invokestatic,invokespecial指令调用的方法都是在加载阶段被替换为直接引用:
    • invokestatic指令: 用来调用static方法;
    • invokespecial指令: 用于调用私有实例方法、构造器,以及使用 super 关键字调用父类的实例方法或构造器,和所实现接口的默认方法。
  • 动态绑定: 在运行阶段(每次类被初始化的时候?)才能确定直接引用的方法.
    • invokevirtual指令: 调用所有的虚方法(即非私有实例方法, 除了static/private/Constructor方法之外的都算作虚方法, 虽然final方法也是由invokevirtual调用但是final方法不属于虚方法)
    • invokeinterface指令: 调用接口方法

单分派 & 多分派

方法的调用者与方法的参数统称为方法的”宗量”, 单分派是根据一个宗量对目标方法进行选择, 多分派是根据多个宗量对目标方法进行选择

单分派是根据一个宗量对目标方法进行选择,多分派是根据多于一个宗量对目标方法进行选择。此外分派还可以根据”动态/静态解析”分为动态分派(运行期)和静态分派(编译期间).
两类分派方式两两组合便构成了静态单分派、静态多分派、动态单分派、动态多分派四种分派情况。

  • 在编译阶段编译器的选择过程,即静态分派过程。这时候选择目标方法的依据有两点:一是方法的接受者(即调用者)的静态类型(基类类型),二是方法参数类型。因为是根据两个宗量进行选择,所以 Java 语言的静态分派属于多分派类型。
  • 运行阶段虚拟机的选择过程,即动态分派过程。由于编译期已经了确定了目标方法的参数类型(编译期根据参数的静态类型进行静态分派),因此唯一可以影响到虚拟机选择的因素只有此方法的参数类型。因为只有一个宗量作为选择依据,所以 Java 语言的动态分派属于单分派类型。