2.4 动态语言支持

这节将要介绍的是Java 7中的一个重要的新特性。这个新特性的特殊之处在于它是对Java虚拟机规范的修改,而不是对Java语言规范的修改。从这个角度来说,这个改动会比之前介绍的Java 7新特性更加复杂,对Java平台的影响也更加深远。这个新特性增强了Java虚拟机中对方法调用的支持。虽然这个特性的直接受益者是Java平台上的动态语言的编译器,但是它对一般应用程序也有重大的影响,最直接的就是提供了比反射API更加强大的动态方法调用能力。本节将会详细介绍这个Java 7的重要新特性,所涉及的内容包括Java虚拟机中新的方法调用指令invokedynamic,以及Java SE 7核心库中的java.lang.invoke包。这一个新特性对应的修改内容包含在JSR 292(Supporting Dynamically Typed Languages on the JavaTMPlatform)中。

2.4.1 Java语言与Java虚拟机

在介绍新特性之前,首先需要简单介绍一下Java虚拟机。Java虚拟机本身并不知道Java语言的存在,它只理解Java字节代码格式,即class文件。一个class文件包含了Java虚拟机规范中所定义的指令和符号表。Java虚拟机只是负责执行class文件中包含的指令。而这些class文件可以由Java语言的编译器生成,也可以由其他编程语言的编译器生成,还可以通过工具来手动生成。只要class文件的格式是符合规范的,Java虚拟机就能正确执行它。

Java虚拟机的存在实际上是在底层操作系统和应用程序之间添加了一个新的抽象层次。对于一种编程语言来说,可以选择直接把源代码编译成目标平台上的机器代码。这种做法无疑是效率最高的。但是所带来的问题是生成的二进制内容无法兼容不同平台,且实现的复杂度也很高。如果存在某种虚拟机,事情就会变得简单很多。首先虚拟机提供了一个抽象层次,屏蔽了底层系统的差别,其所暴露的接口是规范而统一的,可以真正实现“编写一次,到处运行”的目标。另外,虚拟机会提供很多编程语言所需要的运行时支持能力,包括内存管理、安全机制、并发控制、标准库和工具等。最后,使用一个已有的虚拟机作为运行平台,使编程语言的使用者可以复用与这个虚拟机平台相关的已有资产,包括相关的工具、集成开发环境和开发经验等。这有利于编程语言本身的推广和普及。

正因为如此,已经有非常多的编程语言支持把Java虚拟机作为目标运行平台。也就是说,这些语言的编译器支持把源代码编译成Java字节代码,其中比较主流的语言包括Java、Scala、JRuby、Groovy、Jython、PHP、C#、JavaScript、Tcl和Lisp等。这其中最主流的还是Java语言本身。

前面虽然说到Java虚拟机并不关心字节代码是由哪种编程语言产生的,但是Java语言作为Java虚拟机上的第一个也是最重要的一种语言,它对Java虚拟机规范本身所产生的影响是最大的。事实上,Java虚拟机上的很多特性,是为了配合Java语言而产生的。Java语言作为一门静态类型的编程语言,也影响了Java虚拟机本身的动态性。随着越来越多的动态类型编程语言将Java虚拟机作为运行平台,而Java虚拟机本身又缺乏对动态性的支持,所以会对这些动态类型语言的实现产生比较大的阻碍。当然,动态类型语言的实现者总是能找到方法绕开Java虚拟机中的各种限制,这样做所带来的后果就是复杂度比较高,性能也会受到影响。Java 7中的动态语言支持,就是在Java虚拟机规范这个层次上进行修改,使Java虚拟机对于动态类型编程语言来说更加友好,性能也更好。

JSR 292中包含的相关改动涉及应用程序运行中最常见的方法调用。具体来说主要是两个部分,一个是Java标准库中新的方法调用API,另外一个是Java虚拟机规范中新的invokedynamic指令。在下面的内容中,先介绍相关的Java API,因为对一般的开发者来说,这个是用得最多的。随后也会对invokedynamic指令进行具体的介绍。首先从方法句柄开始介绍。