虚拟机字节码执行引擎【动态类型语言支持(二)】

java.lang.invoke包

动态类型方法调用的底层问题终归是应当在Java虚拟机层次上去解决才是最合适的。因此,在Java虚拟机层面上提供动态类型的直接支持就成为Java平台发展必须解决的问题,所以才有了java.lang.invoke包。

JDK7时新加入的java.lang.invoke包是JSR 292的一个重要组成部分,主要目标是之前单纯依靠符号引用来确定调用的目标方法这条路之外,提供一种新的动态确定目标方法的机制,称为“方法句柄”(Method Handle)。

举个例子,要实现一个带谓词(谓词就是由外部传入的排序时比较大小的动作)的排序函数,在C/C++中常引用做法是把谓词定义为函数,用函数指针来把谓词传递到排序方法,如下:

void sorr(int list[],const int size,int (*compare)(int ,int))

Java语言中做不到这一点,没办法单独把一个函数作为参数进行传递。普遍的做法是设计一个带有compare()方法的Comparator接口,以实现这个接口的对象作为参数,如Java类库中的Collections::sort()方法如下定义:

void sort(List list,Comparator c)

在拥有方法句柄之后,Java语言也可拥有类似于函数指针或委托的方法别名这样的工具了。以下代码演示了句柄的基本用法,无论obj是何种类型(临时定义的ClassA抑或是实现PrintStream接口的实现类System.out),都可正确调用到printIn()方法。

package com.test;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;

/**
 * JSR 292 MethodHandle基础用法演示
 * @author huyl
 *
 */
public class MethodHandleTest {

    static class ClassA{
        public void printIn(String s){
            System.out.println(s);
        }
    }
    
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, Throwable {
        Object obj = System.currentTimeMillis() % 2 == 0 ? System.out : new ClassA();
        //无论obj最终是哪个实现类,下面这句都能正确调用到printIn方法
        getPrintInMH(obj).invokeExact("icyfenix");
    }
    
    private static MethodHandle getPrintInMH(Object reveiver) throws NoSuchMethodException, IllegalAccessException{
        /* MethodType:代表“方法类型”,包含了方法的返回值(methodType()的第一个参数)
         * 和具体参数(methodType()的第二个参数)
         */
        MethodType mt = MethodType.methodType(void.class, String.class);
        /* lookup()方法来自于MethodHandles.lookup,这句的作用在指定类中查找符合给定的
         * 方法名称、方法类型,并且符合调用权限的方法句柄。
         * 因为这里调用的是一个虚方法,按照Java语言的规则,方法第一个参数是隐式的,代表该方法的
         * 接收者,也即this指向的对象,这个参数以前是放在参数列表中进行传递,现在提供bindTo()
         * 方法来完成这件事情
         */
        return MethodHandles.lookup().findVirtual(reveiver.getClass(),"printIn",mt).bindTo(reveiver);
    }
}

方法getPrintInMH()中实际上是模拟了invokevirtual指令的执行过程,只不过它的分派逻辑并非固话在Class文件的字节码上,而是通过一个由用户设计的Java方法来实现,而这个方法本身的返回值(MethodHandle对象),可以视为对最终调用方法的一个“引用”。由此为基础,有了MethodHandle就可写成类似C/C++那样的函数声明了:

void sort(List list,MethodHandle compare)

仅站在Java语言的角度看,MethodHandle在使用方法和效果上与Reflection有众多相似之处,不过他们也有以下区别:

  1. Reflection和MethodHandle机制本质上都是在模拟方法调用,但是Reflection是在模拟Java代码层次的方法调用,而MethodHandle是在模拟字节码层次的方法调用。在MethodHandles.lookup上的3个方法findStatic()、findVirtual()、findSpecial()正是为了对应于invokestatic、invokevirtual(以及invokeinterface)和invokespecial这几条字节码指令的执行权限检验行为,而这些底层细节在使用Reflection API时是不需要关心的。
  2. Reflection中的java.lang.reflect.Method对象远比MethodHandle机制中的java.lang.invoke.MethodHandle对象所包含的信息来的多。前者是方法在Java端的全面映像,包含了方法的签名、描述符 以及方法属性表中各种属性的Java端表示方式,还包含了执行权限等的运行期信息。而后者仅包含执行该方法的相关信息。Reflection是重量级的,MethodHandle是轻量级的。
  3. 由于MethodHandle是对字节码的方法指令调用的模拟,那理论上虚拟机在这方面做的各种优化(如方法内联),在MethodHandle上也应当可采用类似思路去支持(目前还在完善中),而通过反射去调用方法则几乎不可能直接去 实施各类调用点优化措施。

除了上诉区别,去除“仅站在Java语言的角度看”:Reflection API的设计目标是只为Java语言服务的,而MethodHandle则设计为可服务于所有Java虚拟机之上的语言,其中也包括了Java语言而已,而且Java在这里离并不是主角。

《深入理解Java虚拟机》第三版 学习

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,287评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,346评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,277评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,132评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,147评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,106评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,019评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,862评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,301评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,521评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,682评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,405评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,996评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,651评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,803评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,674评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,563评论 2 352

推荐阅读更多精彩内容